【问题标题】:Convert specific query into JPQL or Criteria Builder query将特定查询转换为 JPQL 或 Criteria Builder 查询
【发布时间】:2020-06-08 11:02:08
【问题描述】:

这是 2 个实体的代码(它在数据库中生成三个表)。 Book 实体:

@Entity
public class Book {
    @Id
    private long id;

    private String name;

    @ManyToMany
    private List<Author> authors;
}

Author 实体:

@Entity
public class Author {
    @Id
    private long id;

    @Column(unique=true)
    private String name;
}

我正在尝试按作者列表查找书籍。这是一个sql查询:

select book.id, ARRAY_AGG(author.name)
from book 
join book_authors ba on book.id=ba.book_id 
join author on ba.authors_id=author.id
group by book.id
having  ARRAY_AGG(distinct author.name order by author.name)=ARRAY['a1', 'a2']::varchar[]

['a1', 'a2'] 是书籍作者列表,必须作为参数传递。这个想法是聚合作者,然后将它们与传递的参数列表进行比较。

如何将此 SQL 查询重写为 JPQL 或 CriteriaBuilder 查询?

【问题讨论】:

    标签: spring-data-jpa jpql hibernate-criteria


    【解决方案1】:
    @Query("select distinct b from Book b join b.authors a where a.name in(:names)")
    List<Book> findByAuthorsNames(@Param("names") List<String> names)
    

    如果你想获取b.authors 使用join fetch 而不是join

    【讨论】:

    • 这么简单?太好了!
    • 虽然没有,在这种情况下,如果我们在数据库中有 [a1, a2] 并通过 [a1, a3] 搜索,我们会找到一本书。相反,完全匹配是必要的。
    • 在这种情况下可以选择Criteria APISpecification。我已经回答过一次了
    【解决方案2】:

    如果需要完全匹配,您可以像这样使用Specification

    public class BookSpecifications {
            public static Specification<Book> byAuthorsNames(List<String> names) {
                return (root, query, builder) -> {
                    Join<Book, Author> author = root.join("authors", JoinType.LEFT);
    
                    Predicate predicate = builder.conjunction;
                    for(String name : names) {
                        Predicate namePredicate = builder.and(author.get("name"), name);
                        predicate = builder.and(predicate, namePredicate);
                    }
    
                    return predicate;
                }
            }
    }
    

    BookRepository 必须扩展 JpaSpecificationExecutor

    用法:

    BookRepository repository;
    
    public List<Book> findByAuthorsNames(List<String> names) {
        return repository.findAll(BookSpecifications.byAuthorsNames(names));
    }
    

    【讨论】:

    • 这转换为 select book0_.id as id1_1_, book0_.name as name2_1_, book0_.visit_id as visit_id3_1_ from book book0_ left outer join book_authors authors1_ on book0_.id=authors1_.book_id left outer join author author2_在 authors1_.authors_id=author2_.id 上 1=1 和 author2_.name=?和 author2_.name=?
    • 结果是否符合预期?您的 SQL 脚本包含特定于数据库的函数 ARRAY_AGG。没有办法在 JPQL 语句中使用它。因此,您可以使用 JPQL 获得相同的结果,但不能使用相同的 SQL。您应该使用本机查询而不是 JPQL
    猜你喜欢
    • 2021-10-09
    • 2011-06-12
    • 2019-04-18
    • 2013-09-17
    • 2021-04-03
    • 2017-10-29
    • 2011-09-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多