如何将spring数据jpa规范查询中的distinct和sort与join结合起来

Posted

技术标签:

【中文标题】如何将spring数据jpa规范查询中的distinct和sort与join结合起来【英文标题】:How to combine distinct and sort in spring data jpa specification query with joins 【发布时间】:2020-06-06 02:17:48 【问题描述】:

设置示例:

实体

@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

Author 和 Publisher 都是只有 id 和 name 的简单实体。

spring data jpa BookSpecification:(注意查询时的不同)

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()
        
    

执行查询(可分页,包含对 publisher.name 的排序)

bookRepository.findAll(
    Specification.where(bookSpecification.hasAuthors(searchRequest)),
    pageable!!)

REST 请求:

MockMvcRequestBuilders.get("/books?authors=Jane,John&sort=publisherName,desc")

这会导致以下错误:

Caused by: org.h2.jdbc.JdbcSQLSyntaxErrorException: Order by expression "PUBLISHERO3_.NAME" must be in the result list in this case;

问题在于 distinct 和 sort 的组合。 distinct 要求发布者名称位于选择字段中才能进行排序。

如何使用规范查询解决此问题?

【问题讨论】:

【参考方案1】:

你不能这样做。基本上,如果您有不同的并且想要排序,则只能使用选定的列。

你可以做的是使用row_number()窗口函数而不是distinct,然后用row_number=1选择所有内容。 你可以在这里找到一个(有点旧的)例子:https://***.com/a/30827497/10668681

【讨论】:

【参考方案2】:

您可能必须像这样显式选择PUBLISHERO3_.NAME 列:

query.select(builder.array(root.get("PUBLISHERO3_.NAME"), root.get("yourColumnHere")));

默认情况下可能不包含连接的列,因为它们超出了根泛型类型的范围。

【讨论】:

以上是关于如何将spring数据jpa规范查询中的distinct和sort与join结合起来的主要内容,如果未能解决你的问题,请参考以下文章

Spring Data JPA:创建规范查询获取连接

处理 JPA 规范和 spring-data-jpa 时如何使用声明 Stream 作为返回类型

使用 Spring JPA 规范按子查询排序

Spring Data JPA方法定义规范

使用连接表存储库的@manytomany 中的 Spring 数据 jpa 规范和可分页

使用 Spring JPA 规范进行多列搜索