2016-04-19 7 views
0

Ich habe eine Entität, die eine Liste von Elementen enthält, und jetzt möchte ich über Attribute dieser Elemente suchen. Diese Einschränkung sollte "und" verbunden sein. Bitte beachten Sie dieses einfache Beispiel:JPA CriteriaBuilder finde Entität, die Elemente mit bestimmten Attributen in der Sammlung hat

@Entity 
public class Parent { 

    @Column 
    @Enumerated(EnumType.STRING) 
    private City city; 

    @OneToMany(...) 
    private List<Children> childrens; 
} 

@Entity 
public class Children { 

    @Column 
    @Enumerated(EnumType.STRING) 
    private School school; 

    @Column 
    private Integer yearInSchool; 

}  

Jetzt mag ich Eltern in einer bestimmten Stadt zu finden, läßt „BigCity“ sagt mit Kindern in der Schule „AwesomeSchool“, die in der Klasse/Jahr 6. Ich mag um die Suche bekommen Ergebnis nur über CriteriaBuilder.

Bisher habe ich:

final CriteriaBuilder c = getCriteriaBuilder(); 
final CriteriaQuery<Parent> query = c.createQuery(Parent.class); 
final Root<Parent> r = query.from(Parent.class); 
query.select(r) 
     .where(c.and(c.equal(r.get("city"), City.BigCity)), 
       c.equal(r.get("childrens").get("school"), School.AwesomeSchool), 
       c.equal(r.get("childrens").get("yearInSchool"), 6)); 

Leider gibt es zwei Probleme: - es sieht aus wie ich nicht get("school") auf der Liste Attribut aufrufen können - dies wird alle Eltern mit Kindern zurückkehren, die entweder in "AwesomeSchool" oder sind 6 Jahre in der Schule.

Können Sie mir bitte helfen? Ich habe darüber nachgedacht, einen Join zu verwenden, aber da ist die gleiche Frage: Wie kann ich den where Teil des Joins definieren, so dass er beide Attribute (school und yearInSchool) gleichzeitig erfüllen muss. Ich habe ähnliche Artikel über die Abfrage von Objekten gefunden, deren Kinder eine Bedingung erfüllen - aber hier müssen die Kinder zwei Bedingungen gleichzeitig erfüllen.

Update 1 Wenn ich eine Verknüpfung verwenden, um z. Ich die „Schule“ von einem Kind, bekomme so weit über das Prädikat:

Predicate predicate = r.join("childrens").get("school").in(School.AwesomeSchool) 

Wie kann ich wieder verwende dieses Objekt für die zweite Filterbedingung zu behaupten verbunden ist auch?

+0

, wie Sie es haben zur Zeit werden Sie zu einem Zeitpunkt eine Bedingung auf das Kind zu erfüllen, so Kind 1 kann eine Bedingung erfüllen, aber Kind 2 eine weitere Bedingung . Sie möchten, dass das gleiche Kind beide Bedingungen erfüllt. Daher müssen Sie einen Join verwenden und das verbundene Objekt in der zweiten und dritten where-Klausel verwenden. Es lohnt sich, es als JPQL zu schreiben, bevor der Criteria-Teil ausgeführt wird. –

+0

Hallo Neil, danke für deinen Kommentar. Ja, du hast mein Problem vollkommen verstanden. Ich habe die Frage mit einem Join für eine Bedingung aktualisiert. Wie kann ich dieses Objekt wiederverwenden, um nach der zweiten Bedingung zu filtern? –

Antwort

1

Sie müssen JOIN und dann verwenden Sie das JOIN Objekt, das Sie erhalten, wenn Sie die Verbindung bilden, wenn Sie die WHERE Klauseln bilden.

Join childrenJoin = r.join("childrens"); 

query.where(c.and(c.equal(r.get("city"), City.BigCity)), 
       c.equal(childrenJoin.get("school"), School.AwesomeSchool), 
       c.equal(childrenJoin.get("yearInSchool"), 6)); 

Vielleicht können Sie einen JPQL sein:

SELECT p FROM Parent p JOIN p.childrens c 
WHERE p.city = :theCity AND c.school = :theSchool AND c.yearInSchool = 6 
+0

Danke. Ich werde es versuchen. Aber wenn ich das hier lese, würde dies nicht auch ein Elternteil "P" zurückgeben, wenn dieser Elternteil zwei Kinder hat, eins in "AwesomeSchool" und Klasse 10 und das zweite in "SomeotherSchool" und Klasse 6? Wenn ich mir die Eltern anschaue, ist die Bedingung erfüllt: Elternteil P hat ein Kind in AwesomeSchool und ein Kind in Jahr 6. –

Verwandte Themen