2016-05-03 6 views
0

Ich versuche, dynamische Abfragen mit JPA und Criteria API, aber ohne Metamodelle zu erstellen.LINKER JOIN mit AND-Operator unter Verwendung der Kriterien-API

Mit den Tabellen:

Foo: 
ID 
1 
2 
3 
4 

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

Ich möchte alle Einheiten Foo abzurufen, wo keine passende Bar Nummer hat 44 (Erwartet Foo 1, 3, 4)

Die SQL sollte in etwa so aussehen:

select distinct * 
from Foo foo0_ 
left join Bar bar0_ on foo0_.ID=bar0_.FooID and bar0_.Number=44 
where bar0__.id is null; 

Mein Code sieht in etwa wie folgt aus:

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(); 

Aber das erzeugt diese 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); 

und gibt keine Foo.

Irgendwelche Ideen? Vielen Dank!

Antwort

1

Sie geben nicht an, für welche JPA-Implementierung das gedacht ist, und klarerweise kann die SQL für jede davon abweichen.

Abgesehen davon ist Ihr Beitritt falsch. Jeder Aufruf join wird ein JOIN, und Sie wollen nur 1 Join, wenn das, was Sie schreiben, korrekt ist. Sie können auch JPA 2.1 "ON" -Bedingungen für den Join verwenden (anstatt ihn in die WHERE zu setzen).

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); 

Dann machen Sie das gleiche wie Ihre Frage mit Ausnahme der barJoin; keine Ahnung, was diese UND/ODER-Bedingungen zu tun versuchen - Ihre vorgeschlagene SQL hat nichts davon.

+0

Ich benutze Hibernate JPA 2.0 so funktioniert leider barJoin.on (onCond) nicht. Die Prädikate _and_, _or_ und _all_ dienen zum Erstellen dynamischer Abfragen in verschiedenen Tabellen und mit unterschiedlichen Parametern. – Solver42

+0

Geändert zu JPA 2.1 und verwendet Ihren Code aber qb zu cb geändert und ich bekomme AbstractMethodError: org.hibernate.ejb.criteria.path.ListAttributeJoin.on (Ljavax/Persistenz/Kriterien/Ausdruck;) Ljavax/Persistenz/Kriterien/Join; Ist qb ein QueryBuilder und brauche ich einen? Kann es in der JPA-Abhängigkeit nicht finden. – Solver42

+0

Ja, Sie haben JPA 2.1 "ON" Bedingungen und ich "geändert zu JPA 2.1", weil ich es richtig machen will, aber ich kann es nicht zum Laufen bringen. Was ist qb? – Solver42

Verwandte Themen