I have these entities
@Entity
@Table(name = "Item")
class Item(
@Column(name = "name", nullable = false)
var name: String,
@Column(name = "added_date", columnDefinition = "TIMESTAMP WITH TIME ZONE", nullable = true)
var addedDate: ZonedDateTime? = null,
@Column(name = "duration", nullable = true)
var duration: Int? = null,
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "head_of_id", nullable = false)
val headOf: HeadOf,
) {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
var id: Long = 0
}
@Entity
@Table(name = "head_of")
class HeadOf(
@Column(name = "company", nullable = false)
var company: String,
@Column(name = "city", nullable = false)
var city: String,
@Column(name = "age", nullable = true)
var age: Int?
) {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
var id: Long = 0
}
and this is the corresponding repository
interface ItemRepository : JpaRepository<Item, Long> {
fun findByHeadOfIdAndAddedDateNotNullOrDurationNotNull(
headOfId: Long,
position: ScrollPosition,
pageable: Pageable,
): Window<Item>
}
This is what is currently in the table Item
. Its one row (its the result of a dump
)
INSERT INTO public.item VALUES (1, 'Some fancy title', '2024-12-31 07:14:42.955789+00', NULL, 1000);
As you can see, headOf
is 1000L
.
Now, when I call this function findByHeadOfIdAndAddedDateNotNullOrDurationNotNull
with the following values
headOfId: 0 scrollPosition: ScrollPosition.of(...) PageRequest.of(0, 10)
it returns me that one row that is in there. I do not expect that, because the headOfId
I am passing is 0L
and not 1000L
.
I cannot use a @Query
annotation, then I get this
Could not create query for public abstract org.springframework.data.domain.Window org...jpa.repository.ItemRepository.findByHeadOfIdAndAddedDateNotNullOrDurationNotNull(long,org.springframework.data.domain.ScrollPosition,org.springframework.data.domain.Pageable); Reason: Scroll queries are not supported using String-based queries
Is there a solution to this?
The problem is operator precedence in SQL. It gets evaluated like this
SELECT ... FROM ... WHERE (headOfId === :headOfId AND addedDate NOT NULL) OR duration NOT NULL
The soultion to this is to write the query in this way (which is ugly, but it works)
interface ItemRepository : JpaRepository<Item, Long> {
fun findByHeadOfIdAndAddedDateNotNullOrHeadOfIdAndDurationNotNull(
headOfId1: Long,
headOfId2: Long,
position: ScrollPosition,
pageable: Pageable,
): Window<Item>
}
You also might be able to do it with the Criteria API
.