Example setup:
Entity
@Entity
class Book {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
var id: Long? = null
@ManyToMany(cascade = [CascadeType.PERSIST, CascadeType.MERGE])
@JoinTable(name = "book_authors",
joinColumns = [JoinColumn(name = "book_id")],
inverseJoinColumns = [JoinColumn(name = "author_id")])
var authors: MutableSet<Author> = HashSet()
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "publisher_id")
lateinit var publisher: Publisher
}
Both Author and Publisher are simple entities with just an id and a name.
The spring data jpa BookSpecification: (notice the distinct on query)
fun hasAuthors(authorNames: Array<String>? = null): Specification<Book> {
return Specification { root, query, builder ->
query.distinct(true)
val matchingAuthors = authorRepository.findAllByNameIn(authorNames)
if (matchingAuthors.isNotEmpty()) {
val joinSet = root.joinSet<Book, Author>("authors", JoinType.LEFT)
builder.or(joinSet.`in`(matchingContentVersions))
} else {
builder.disjunction()
}
}
}
Executing the query (pageable containing a sort on publisher.name)
bookRepository.findAll(
Specification.where(bookSpecification.hasAuthors(searchRequest)),
pageable!!)
The REST request:
MockMvcRequestBuilders.get("/books?authors=Jane,John&sort=publisherName,desc")
This results in the following error:
Caused by: org.h2.jdbc.JdbcSQLSyntaxErrorException: Order by expression "PUBLISHERO3_.NAME" must be in the result list in this case;
The problem is in the combination of the distinct and sort. The distinct requires the publisher name to be in the select fields to be able to sort.
How can I fix this with Specification query?