2016-05-03 5 views
0

Я пытаюсь построить динамические запросы с использованием JPA и API критериев, но без метамоделей.LEFT JOIN с оператором AND с использованием критериев API

С таблицами:

Foo: 
ID 
1 
2 
3 
4 

Bar: 
ID FooID Number 
1 2  44 
2 2  55 
3 3  55 

Я хочу, чтобы получить все объекты Foo, где нет соответствия Бар не имеет номер 44. (Ожидая 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); 

и не возвращает Foo.

Любые идеи? Спасибо!

ответ

1

Вы не указали, для какой реализации 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 не имеет ничего такого.

+0

Я использую Hibernate JPA 2.0, поэтому, к сожалению, barJoin.on (onCond) не работает. Предикаты _and_, _or_ и _all_ предназначены для построения динамических запросов в разных таблицах и с различными параметрами. – Solver42

+0

Изменен на JPA 2.1 и использовал ваш код, но изменил qb на cb, и я получаю AbstractMethodError: org.hibernate.ejb.criteria.path.ListAttributeJoin.on (Ljavax/persistence/criteria/Expression;) Ljavax/persistence/criteria/join; Является ли qb QueryBuilder и мне нужен он? Невозможно найти его в зависимости от JPA. – Solver42

+0

Да, вы отметили условия JPA 2.1 «ON», и я «Изменен для JPA 2.1», потому что я хочу сделать это правильно, но я не могу заставить его работать. Что такое qb? – Solver42

 Смежные вопросы

  • Нет связанных вопросов^_^