【问题标题】:Problem trying to construct JPA query from SQL尝试从 SQL 构造 JPA 查询时出现问题
【发布时间】:2019-09-25 10:23:14
【问题描述】:

我有一个在 SQL 中运行良好的查询,但我似乎无法在 JPA 中创建等效的查询。 CriteriaBuilder“或”似乎没有执行“或”。

这些是表格...

Table A

id : Long : primary key
b_id : Long : foreign key to id of Table B
c_id : Long : foreign key to id of Table C

Table B

id: Long : primary key
loc_id: Long 

Table C

id: Long : primary key
d_id : Long : foreign key to id of Table D

Table D

id: Long : primary key
loc_id: Long 

这是表格中的数据(按列出的字段顺序)...

Table A:
1,  1,  null
2,  2,  null
3,  null,   1

Table B:
1,  5
2,  6

Table C:
1,  1

Table D:
1,  5

我的 sql 查询通过外键查找表 B 或表 D 中 loc_id 为 5 的表 A 中的所有记录。 (2 个结果 - 第 1 行和第 3 行)

select * from A 
LEFT JOIN B on B.id = a.b_id
LEFT JOIN C on C.id = a.c_id
LEFT JOIN D on D.id = c.d_id
WHERE B.loc_id = 5 or D.loc_id = 5

但是,我正在努力在 JPA 中编写相同的结果。 我在下面尝试过创建 2 个谓词,它们在单独执行时都找到 1 条记录,但是当我“或”它们时它会产生 0 条记录。这怎么可能是对的?

EntityManager em = getEntityManager();
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery cq = cb.createQuery();
Root<A> rt = cq.from(A.class);
List<Predicate> predicates = new ArrayList<>();

Join<B, A> join1 = rt.join("b_id", JoinType.INNER);
Join<C, A> join2 = rt.join("c_id", JoinType.INNER);
Join<D, C> join3 = join2.join("d_id", JoinType.INNER);
predicates.add(cb.or(cb.equal(join1.get("loc_id"), 5), cb.equal(join3.get("loc_id"), 5)));

CriteriaQuery x = cq.select(rt).where(predicates.toArray(new Predicate[predicates.size()]));
Query q = em.createQuery(x);
List<A> = q.getResultList();

感谢所有建议,谢谢....

【问题讨论】:

  • 你不需要JoinType.LEFT吗?
  • 是的 - 已经解决了 - 谢谢。

标签: sql jpa join predicate


【解决方案1】:

解决办法

EntityManager em = getEntityManager();
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<A> cq = cb.createQuery(A.class);
Root<A> rt = cq.from(A.class);

Join<B, A> joinB = rt.join("b_id", JoinType.LEFT);
Join<C, A> joinC = rt.join("c_id", JoinType.LEFT);
Join<D, C> joinD = joinC.join("d_id", JoinType.LEFT);

Predicate bPredicate = cb.equal(joinB.get("loc_id"), 5);
Predicate dPredicate = cb.equal(joinD.get("loc_id"), 5);

Predicate predicate = cb.or(bPredicate, dPredicate);

CriteriaQuery<A> x = cq.select(rt).where(predicate);
TypedQuery<A> q = em.createQuery(x);

List<A> result = q.getResultList();

【讨论】:

  • @r.l.我已经编辑了您的问题的解决方案。所有问题都是由可为空的 b 和 c 字段引起的
  • 是的,JoinType.LEFT 是 sp00m 指出的问题。我不确定为什么您之前编写的没有加入的版本不起作用,但有加入的版本可以,所以问题已修复,谢谢。 (我已经删除了上面的 cmets,因为解决方案不再是他们所指的那个)
  • @r.l.以前的版本不起作用,因为它使用 b_id 和 c_id 的交叉连接。但如果其中任何一个为空,则从结果中排除行
猜你喜欢
  • 1970-01-01
  • 2020-11-26
  • 2020-04-02
  • 2016-09-30
  • 2018-07-23
  • 2015-02-26
  • 2015-03-20
  • 1970-01-01
  • 2020-09-27
相关资源
最近更新 更多