java - JPA CriteriaQuery中不需要的交叉连接在子查询中选择
问题描述
当我在子查询中进行选择时,我得到了我认为不必要的交叉连接,这会损害性能。如果这有所作为,我正在使用 Postgres。
我的目标是生成以下查询
select a1.first_name from author a1
where a1.last_name = ?
and (a1.id in
(select distinct b.author_id
from book b
where (b.published_on between ? and ?)
group by b.author_id
having count(b.author_id) >= 2))
但我明白了
select a1.first_name from author a1
where a1.last_name = ?
and (a1.id in
(select distinct b.author_id
from book b
cross join author a2 where b.author_id = a2.id -- <<< I don't want this cross join!
and (b.published_on between ? and ?)
group by b.author_id
having count(b.author_id) >= 2))
代码
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<String> cq = cb.createQuery(Author.class);
Root<Author> authorRoot = cq.from(Author.class);
Subquery<Long> countSubquery = cq.subquery(Long.class);
Root<Book> bookRoot = countSubquery.from(Book.class);
Expression<Long> count = cb.count(bookRoot.get(Book_.author));
countSubquery.select(bookRoot.get(Book_.AUTHOR))
.distinct(true)
.where(cb.between(bookRoot.get(Book_.publishedOn),
LocalDate.of(2021, MARCH, 1),
LocalDate.of(2021, MARCH, 31)))
.groupBy(bookRoot.get(Book_.author))
.having(cb.greaterThanOrEqualTo(count, 2L));
cq.where(
cb.equal(authorRoot.get(Author_.lastName), "Smith"),
cb.in(authorRoot.get(Author_.ID)).value(countSubquery));
cq.select(authorRoot.get(Author_.FIRST_NAME));
TypedQuery<String> query = entityManager.createQuery(cq);
return query.getResultList();
实际上,我正在从用户驱动的查询生成器生成查询,这段代码重新创建了我遇到的确切问题。
使用查询生成器时,用户最终可能会在子查询中进行多项选择,因此我需要它尽可能地执行。
我不明白为什么我的查询需要任何连接/交叉连接才能工作。
实体
@Entity
public class Author {
@Id
@GeneratedValue
private Long id;
private String firstName;
private String lastName;
@OneToMany(mappedBy = "author", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private Set<Book> books;
}
@Entity
public class Book {
@Id
@GeneratedValue
private Long id;
private String name;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "author_id")
private Author author;
private LocalDate publishedOn;
}
解决方案
此表达式:bookRoot.get(Book_.author)
表示您正在隐式Author
加入。Book
要摆脱额外的连接,您将不得不使用本机查询,或者Book.author_id
再次映射为一个简单的列:
@Column(name = "author_id", insertable = false, updatable = false)
private Long authorId;
并Book_.authorId
改为使用。
推荐阅读
- javascript - 根据时间戳获取今天和昨天的项目
- ms-access - 取消form.unload事件时如何返回到指定控件?
- python - 维护 PyPDF2 的替代品
- java - 添加用户字段后的 StackOverflowError
- javascript - 如何使用 imagepack 在 React Native 中上传文件
- python - 如果用户选择了错误的文件类型,如何显示错误消息?
- opencv - msvc 试图编译 cv::Matx
作为 4 元素向量 - c# - 需要指导使用 Azure Ad 将 Blazor Web 应用发布到 Azure 以进行身份验证
- apache-nifi - Nifi:NIFI 中的 Json 到 CSV 转换器
- json - 在对行执行删除操作后使用 table.ajax.reload() 不会刷新表