LEFT JOIN 与 AND 运算符使用 Criteria API
LEFT JOIN with AND operator using Criteria API
我正在尝试使用 JPA 和 Criteria API 但没有元模型来构建动态查询。
附表:
Foo:
ID
1
2
3
4
Bar:
ID FooID Number
1 2 44
2 2 55
3 3 55
我想检索所有没有匹配 Bar 的编号为 44 的 Foo 实体。(期望 Foo 1、3、4)
SQL 应该看起来像这样:
select distinct *
from Foo foo0_
left join Bar bar0_ on foo0_.ID=bar0_.FooID and bar0_.Number=44
where bar0__.id is null;
我的代码看起来像这样:
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Foo> cq = cb.createQuery(Foo.class);
Root<Foo> fooRoot = cq.from(Foo.class);
cq.select(fooRoot).distinct(true);
List<Predicate> allPredicates = new ArrayList<Predicate>();
List<Predicate> orPredicates = new ArrayList<Predicate>();
List<Predicate> andPredicates = new ArrayList<Predicate>();
andPredicates.add(cb.equal(fooRoot.join("bars", JoinType.LEFT).get("number"), 44));
andPredicates.add(cb.isNull(fooRoot.join("bars", JoinType.LEFT).get("ID")));
orPredicates.add(cb.and(andPredicates.toArray(new Predicate[andPredicates.size()])));
allPredicates.add(cb.or(orPredicates.toArray(newPredicate[orPredicates.size()])));
cq.where(allPredicates.toArray(new Predicate[allPredicates.size()]));
TypedQuery<Foo> query = em.createQuery(cq);
query.getResultList();
但这会生成这个 SQL:
select distinct *
from Foo foo0_
left outer join Bar bar1_ on foo0_.id=bar1_.FooID
left outer join Bar bar2_ on foo0_.id=bar2_.FooID
where bar1_.Number=44 and (bar2_.id is null);
和 returns 没有 Foo.
有什么想法吗?谢谢!
您没有指定这是针对哪个 JPA 实现,显然每个 SQL 可能不同。
除此之外,您的加入是错误的。每个 join
调用都会执行一个 JOIN,如果你写的是正确的,你只需要 1 个连接。您也可以在连接上使用 JPA 2.1 "ON" 条件(而不是将其放在 WHERE 中)。
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Foo> cq = cb.createQuery(Foo.class);
Root<Foo> fooRoot = cq.from(Foo.class);
cq.select(fooRoot).distinct(true);
Join barJoin = fooRoot.join("bars", JoinType.LEFT);
Predicate onCond = cb.equal(barJoin.get("number"), 44);
barJoin.on(onCond);
然后按照你的问题做同样的事情,除了使用 barJoin
;不知道那些 AND/OR 条件试图做什么 - 你建议的 SQL 有 none。
我正在尝试使用 JPA 和 Criteria API 但没有元模型来构建动态查询。
附表:
Foo:
ID
1
2
3
4
Bar:
ID FooID Number
1 2 44
2 2 55
3 3 55
我想检索所有没有匹配 Bar 的编号为 44 的 Foo 实体。(期望 Foo 1、3、4)
SQL 应该看起来像这样:
select distinct *
from Foo foo0_
left join Bar bar0_ on foo0_.ID=bar0_.FooID and bar0_.Number=44
where bar0__.id is null;
我的代码看起来像这样:
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Foo> cq = cb.createQuery(Foo.class);
Root<Foo> fooRoot = cq.from(Foo.class);
cq.select(fooRoot).distinct(true);
List<Predicate> allPredicates = new ArrayList<Predicate>();
List<Predicate> orPredicates = new ArrayList<Predicate>();
List<Predicate> andPredicates = new ArrayList<Predicate>();
andPredicates.add(cb.equal(fooRoot.join("bars", JoinType.LEFT).get("number"), 44));
andPredicates.add(cb.isNull(fooRoot.join("bars", JoinType.LEFT).get("ID")));
orPredicates.add(cb.and(andPredicates.toArray(new Predicate[andPredicates.size()])));
allPredicates.add(cb.or(orPredicates.toArray(newPredicate[orPredicates.size()])));
cq.where(allPredicates.toArray(new Predicate[allPredicates.size()]));
TypedQuery<Foo> query = em.createQuery(cq);
query.getResultList();
但这会生成这个 SQL:
select distinct *
from Foo foo0_
left outer join Bar bar1_ on foo0_.id=bar1_.FooID
left outer join Bar bar2_ on foo0_.id=bar2_.FooID
where bar1_.Number=44 and (bar2_.id is null);
和 returns 没有 Foo.
有什么想法吗?谢谢!
您没有指定这是针对哪个 JPA 实现,显然每个 SQL 可能不同。
除此之外,您的加入是错误的。每个 join
调用都会执行一个 JOIN,如果你写的是正确的,你只需要 1 个连接。您也可以在连接上使用 JPA 2.1 "ON" 条件(而不是将其放在 WHERE 中)。
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Foo> cq = cb.createQuery(Foo.class);
Root<Foo> fooRoot = cq.from(Foo.class);
cq.select(fooRoot).distinct(true);
Join barJoin = fooRoot.join("bars", JoinType.LEFT);
Predicate onCond = cb.equal(barJoin.get("number"), 44);
barJoin.on(onCond);
然后按照你的问题做同样的事情,除了使用 barJoin
;不知道那些 AND/OR 条件试图做什么 - 你建议的 SQL 有 none。