2013-04-13 2 views
13

Ich möchte eine Abfrage, wo ich zwei Tabellen mit dem CriteriaBuilder beitreten. In MySQL die Abfrage versuche ich, wie diese aussehen würde, zu machen:Wie wird ein CriteriaBuilder-Join mit einer benutzerdefinierten "Ein" -Bedingung erstellt?

SELECT * FROM order 
LEFT JOIN item 
ON order.id = item.order_id 
AND item.type_id = 1 

Ich möchte alle Aufträge bekommen, und wenn sie ein Element des Typs # 1 haben, möchte ich mit diesem Element verbinden. Wenn jedoch kein Artikel vom Typ # 1 gefunden wird, möchte ich trotzdem die Bestellung erhalten. Ich kann nicht herausfinden, wie man das mit dem CriteriaBuilder macht. Alles, was ich weiß, wie zu machen:

CriteriaBuilder cb = em.getCriteriaBuilder(); 
CriteriaQuery<Order> cq = cb.createQuery(Order.class); 
Root<Order> order = cq.from(Order.class); 
Join<Order, Item> item = order.join(Order_.itemList, JoinType.LEFT); 
Join<Item, Type> type = order.join(Item_.type, JoinType.LEFT); 
cq.select(order); 
cq.where(cb.equal(type.get(Type_.id), 1)); 

Diese Abfrage pleite ist, da es sich in so etwas wie dies in MySQL Ergebnisse:

SELECT * FROM order 
LEFT JOIN item 
ON order.id = item.order_id 
WHERE item.type_id = 1 

Das Ergebnis wird nur mit Elementen des Typs # 1 enthalten Aufträge. Bestellungen ohne sind ausgeschlossen. Wie kann ich den CriteriaBuilder verwenden, um eine Abfrage wie im ersten Beispiel zu erstellen?

+0

_Ich möchte alle Bestellungen erhalten und wenn sie einen Artikel vom Typ # 1 haben, sollte dieser Artikel in result_ enthalten sein. Welcher Ergebnistyp möchten Sie? Auftrag? Oder ein Tupel/Multiselect? Was willst du _mehr_ als alle Bestellungen? Bitte erläutern Sie – perissf

+0

Entschuldigung, ich war nicht sehr klar. Ich habe die Beschreibung korrigiert. Ich bin nicht wirklich daran interessiert, den Gegenstand als Teil meines Ergebnisses zu bekommen. Ich möchte nur Bestellungen in meinem Ergebnis. Grundsätzlich möchte ich das Ergebnis basierend auf Artikeln eines bestimmten Typs sortieren und trotzdem Aufträge ohne diese Art von Artikeln erhalten. –

+0

Dies ist mit CriteriaBuilder möglich! Sehen Sie sich meine Antwort an unter – Mitchapp

Antwort

1

Ich denke, das ist das gleiche Problem wie in dieser Frage gestellt. Es sieht so aus, als ob es in CriteriaBuilder nicht möglich ist. Dies ist in der Hibernate Criteria API möglich, aber das wird Ihnen wahrscheinlich nicht helfen.

JPA Criteria API: Multiple condition on LEFT JOIN

+0

Die erste MySQL ist, was ich CriteriaBuilder generieren soll. Das zweite MySQL repräsentiert, was die gezeigte CriteriaQuery generiert. Wenn ich der zweiten MySQL-Abfrage einfach 'or item.id is null 'hinzufüge, bekomme ich nicht, was ich will. Dadurch würden Bestellungen mit Artikeln ausgeschlossen, die eine von 1 verschiedene Typ-ID aufweisen, und nur Bestellungen mit Artikeln vom Typ 1 oder keine Artikel zurückgeben. –

+0

Ich bekomme es jetzt Bjørn. Ich bearbeite meine Antwort. – carbontax

+0

Danke. Ich könnte es in einem kleineren Maßstab versuchen, aber bei meinem aktuellen Projekt wird es mir wahrscheinlich nicht helfen. Im Moment bin ich auf EclipseLink (JPA 2.0). Soweit ich es herausfinden konnte ([link] (https://blogs.oracle.com/arungupta/entry/jpa_2_1_early_draft)), wird die Funktion, die ich brauche, erst ab JPA 2.1 verfügbar sein. Hoffentlich wird es bald. –

0

Ich weiß, diese Frage eine lange Zeit ein Go gemacht wurde, aber vor kurzem eine hatte das gleiche Problem und ich fand diese Lösung aus einer Oracle-Forum, ich kopiert und eingefügt nur für den Fall der Link nicht mehr verfügbar.

MiguelChillitupaArmijos 29-abr-2011 1.41 (en respuesta ein 840.578) Denken Sie Sie so etwas wie verwenden sollte:

em.createQuery("SELECT DISTINCT e.Id" + 
        " from Email e " + 
        " left join e.idEmailIn e2 *with* e2.responseType = 'response'" + 
        "  where e.type = 'in' and e.responseMandatory = true").getSingleResult(); 

Jahr Dies ist der Link.

JPA Criteria : LEFT JOIN with an AND condition

-1

Es gibt eine Abhilfe, wenn Sie Hibernate verwenden 3.6 mit JPA 2.0 Es ist nicht die bessere Lösung, aber es funktioniert perfekt für mich.

Ich habe die Entität mit der Annotation @Where Hibernate dupliziert. Dies bedeutet, dass Hibernate bei jeder Verwendung der Verknüpfung mit dieser Entität die zusätzliche Bedingung für die Join-Anweisung bei generiertem SQL hinzufügt.

Zum Beispiel zunächst haben wir die Folge Beispiel:

@Entity 
@Table(name = "PERSON") 
public class Person { 

    @Id 
    @Column(name = "PERSON_ID") 
    private Long id; 

    @Id 
    @Column(name = "PERSON_NAME") 
    private String name; 

    @OneToMany(mappedBy = "person", fetch = FetchType.LAZY) 
    private Set<Address> addresses; 

} 

@Entity 
@Table(name = "ADDRESS") 
public class Address { 

    @Id 
    @Column(name = "ADDRESS_ID") 
    private Long id; 

    @Id 
    @Column(name = "ADDRESS_STREET") 
    private String street; 

    @ManyToOne 
    @JoinColumn(name = "PERSON_ID") 
    private Person person; 

} 

Um zusätzliche Bedingungen hinzufügen auf Kriterien Mitglied werden, müssen wir die Adresse @Entity Mapping duplizieren, Hinzufügen der @Where Anmerkung @Where (Klausel = "ADDRESS_TYPE_ID = 2").

@Entity 
@Table(name = "ADDRESS") 
@Where(clause = " ADDRESS_TYPE_ID = 2") 
public class ShippingAddress { 

    @Id 
    @Column(name = "ADDRESS_ID") 
    private Long id; 

    @Id 
    @Column(name = "ADDRESS_STREET") 
    private String street; 

    @OneToOne 
    @JoinColumn(name = "PERSON_ID") 
    private Person person; 

} 

Außerdem müssen wir die doppelte Zuordnungszuordnung für die neue Entität hinzufügen.

@Entity 
@Table(name = "PERSON") 
public class Person { 

    @Id 
    @Column(name = "PERSON_ID") 
    private Long id; 

    @Id 
    @Column(name = "PERSON_NAME") 
    private String name; 

    @OneToMany(mappedBy = "person", fetch = FetchType.LAZY) 
    private Set<Address> addresses; 

    @OneToOne(mappedBy = "person") 
    private ShippingAddress shippingAddress; 

} 

Schließlich können Sie ein in Ihren Kriterien mit diesem speziellen Entity beitreten verwenden:

PersonRoot.join(Person_.shippingAddress, JoinType.LEFT); 

Die Hibernate Snippet SQL sollte wie folgt scheint:

left outer join 
     address shippingadd13_ 
      on person11_.person_id=shippingadd13_.person_id 
      and (
       shippingadd13_.ADDRESS_TYPE_ID = 2 
      ) 
4

Sie CAN tun dass unter Verwendung der on Methode Join<Z, X> on(Predicate... restrictions);. Hier

ist ein funktionierendes Beispiel:

... 
Root<Order> order = cq.from(Order.class); 
Join<Order, Item> item = order.join(Order_.itemList, JoinType.LEFT); 
item.on(cb.equal(item.get(Item_.type), 1)); 
... 
+0

Wenn das funktioniert, werden das einige native Abfragen sein, die ersetzt werden können. Ich probiere es das nächste Mal aus, wenn ich eine Verbindung brauche. –

+0

Ich habe nicht verstanden, was Sie unter "wenige native Abfragen, die ersetzt werden können" verstehen! Probieren Sie es zuerst und Sie werden sehen, dass es perfekt funktioniert! – Mitchapp

+0

Ich meinte nur, dass ich viele Orte habe, an denen ich 'entityManager.createNativeQuery (String)' wegen der Unzulänglichkeiten des CriteriaBuilders verwende. :-) –

0

ON-Klausel wird in Hibernate 4.3-Version unterstützt, jemand ist sich bewusst, wenn ein Parameter Indizierung Problem ist zwischen dem Parameter-Index der zusätzlichen benutzerdefinierten Bedingungen mit dem Index der existierende Mapping-Filter beim Outer-Join mit ON-Klausel?

Verwenden Sie die Person entity Klasse unten als ein Beispiel sagen, dass ich diesen Filter hinzufügen, um die Adresstypen zu begrenzen, und der Filter aktiviert ist, um die IN-Klausel aufzufüllen. Der Parameterindex für die IN-Klausel verursacht das Problem [2], wenn ich zusätzliche Bedingungen (z. B. die Spalte "Straße") zur ON-Klausel hinzufüge. Ist das ein bekanntes Problem?

[1] @filter (name = "Address", Zustand = "ADDRESS_TYPE in (: SupportedTypes)")

[2] Verursacht durch: ERROR 22018: Ungültige Zeichenfolge-Format für Typ BIGINT. private Set-Adressen;

Verwandte Themen