2016-04-15 8 views
1

Ich habe 3 Entitäten.Doppelte verknüpfte Entitäten, die für die übergeordnete Entität abgerufen wurden

  1. Request
  2. RequestDetail
  3. RequestDetailResponse

Request ist einer von vielen RequestDetails (RD vielen einem RH)

RequestDetail ist eines von vielen RequestDetailResponse (RDH vielen einem RD)

Hier sind die Beziehungsdefinitionen:

Request -> RequestDetail (das Feld beachten Sie wird als Sammlung mehr, auf dem später erklärt)

@OneToMany(mappedBy = "requestHeader", fetch = FetchType.EAGER) 
Collection<RequestDetail> requestDetails = new HashSet<>(); 

RequestDetail -> Request

@ManyToOne 
@JoinColumn(name="requestHeaderID") 
private RequestHeader requestHeader; 

RequestDetail -> DetailResponse

@OneToMany(mappedBy = "requestDetail", fetch = FetchType.EAGER) 
Set<DetailResponse> detailResponses = new HashSet<>(); 

DetailResponse -> AnfrageDetail

Meine Frage: Wenn ich eine Sammlung von RequestDetails von einer RequestHeader-Entität (über einen öffentlichen Getter) erhalte, erhalte ich "doppelte" RequestDetails. Wenn man mit sql herumspielt, scheint es, dass die "extra" -Details die Verbindung mit den DetailResponses widerspiegeln. Was bedeutet, dass zum Beispiel

SELECT * FROM RequestHeader rh INNER JOIN RequestDetail rd on  rd.RequestHeaderID = rh.RequestHeaderID 

kehrt, sagen wir, 5 Aufzeichnungen, wo als

SELECT * FROM RequestHeader rh INNER JOIN RequestDetail rd on  rd.RequestHeaderID = rh.RequestHeaderID INNER JOIN DetailResponse drs on drs.RequestDetailID = rd.RequestDetailID 

kehrt, sagen wir, 10, wegen der vielen zu einer DetailResponse Expansion

Als ich das bekommen Sammlung von RequestDetails von meinem RequestHeader-Objekt, bekomme ich eine Größe 10 Sammlung. Wenn ich nun das Feld "RequestDetails" auf der RequestHeader-Entität als Set und nicht als Sammlung deklariere, vermeide ich dieses Problem, aber ich denke, seit ich einen Primärschlüssel für die RequestDetail-Entität definiert habe, sollte die JPA-Verwaltung intelligent genug sein zu wissen, dass es in diesem Zusammenhang kein Duplikat geben kann. Was ich falsch verstanden habe? Verwenden Sie eine Set-Deklaration, um den richtigen Weg zu finden?

Übrigens sind meine Primärschlüssel-Deklarationen, falls sie signifikant sind.

Request:

@Id 
@GeneratedValue(strategy = GenerationType.IDENTITY) 
private Integer requestHeaderID; 

RequestDetail:

@Id 
@GeneratedValue(strategy = GenerationType.IDENTITY) 
private Integer requestDetailID; 

DetailResponse:

 @Id 
    @TableGenerator(name="DetailResponseStore", table="PRIMARY_KEYS", 
pkColumnName = "KEY_NAME", pkColumnValue = "DETAIL_RESPONSE", valueColumnName = "NEXT_VALUE", initialValue = 1, allocationSize = 1) 
@GeneratedValue(strategy = GenerationType.TABLE, generator = "DetailResponseStore") 
private Integer detailResponseID; 

Antwort

0

(Beantwortung meiner Frage)

Die kurze und süße Antwort ist, dass, ja , H ibernate erwartet vom Entwickler, dass Sammlungen keine Duplikate enthalten. Die erste vorgeschlagene Methode ist, wie in der Frage, die Sammlung in einem SET zu speichern.

(dies ist ein FAQ-Thema in der Hibernate Documention (https://developer.jboss.org/wiki/HibernateFAQ-AdvancedProblems#jive_content_id_Hibernate_does_not_return_distinct_results_for_a_query_with_outer_join_fetching_enabled_for_a_collection_even_if_I_use_the_distinct_keyword):

Hibernate nicht zurück unterschiedliche Ergebnisse für eine Abfrage mit Outer-Joins für eine Sammlung aktiviert Holen der (auch wenn ich das deutliche Schlüsselwort)?

Zuerst müssen Sie SQL und wie OUTER JOIN Arbeit in SQL verstehen. Wenn Sie nicht vollständig verstehen und äußere begreifen in SQL verbindet, nicht weiterhin diese FAQ Artikel zu lesen, aber eine SQL-Handbuch oder Tutorial konsultieren Ansonsten werden Sie die folgende Erklärung nicht verstehen und Sie werden sich über dieses Verhalten im Hibernate-Forum beschweren .

Typische Beispiele, die doppelte Referenzen des gleichen Order-Objekt zurückgeben kann:

List result = session.createCriteria(Order.class) 
         .setFetchMode("lineItems", FetchMode.JOIN) 
         .list(); 



<class name="Order"> 
    ... 
    <set name="lineItems" fetch="join"> 

List result = session.createCriteria(Order.class) 
         .list(); 



List result = session.createQuery("select o from Order o left join fetch o.lineItems").list(); 

Alle diese Beispiele die gleiche SQL-Anweisung erzeugen:

SELECT o.*, l.* from ORDER o LEFT OUTER JOIN LINE_ITEMS l ON o.ID = l.ORDER_ID 

Wollen Sie wissen, warum die Duplikate gibt es ? Sehen Sie sich das SQL-Ergebnisset an, Hibernate versteckt diese Duplikate nicht auf der linken Seite des äußeren verknüpften Ergebnisses , sondern gibt alle Duplikate der treibenden Tabelle zurück. Wenn Sie 5 Bestellungen in der Datenbank haben und jede Bestellung 3 Werbebuchungen hat, wird die Ergebnismenge 15 Zeilen sein. Die Java-Ergebnisliste dieser Abfragen hat 15 Elemente, alle vom Typ Auftrag. Nur 5 Order-Instanzen werden von Hibernate erstellt, aber Duplikate des SQL-Resultsets werden als doppelte Verweise auf diese 5 Instanzen beibehalten. Wenn Sie diesen letzten Satz nicht verstehen, müssen Sie sich über Java und den Unterschied zwischen einer Instanz auf dem Java-Heap und einer Referenz auf solch eine Instanz informieren.

(Warum eine linke äußere Verknüpfung? Wenn Sie einen weiteren Auftrag ohne Linie Artikel haben würde, wäre das Ergebnis Satz 16 Zeilen mit NULL sein, die richtige Seite füllt, wobei die Positionsdaten für andere Reihenfolge ist Sie wollen Bestellungen , auch wenn sie keine Werbebuchungen haben, oder? Wenn nicht, verwenden Sie eine innere Verknüpfung holen in Ihrem HQL).

Hibernate filtert diese doppelten Verweise standardmäßig nicht aus. Einige Leute (nicht du) wollen das wirklich. Wie können Sie sie herausfiltern?

So:

Collection result = new LinkedHashSet(session.create*(...).list()); 

A LinkedHashSet Suchfilter erlauben out doppelte Referenzen (es ist ein Satz), und es bewahrt Auftrag (Reihenfolge der Elemente in Ihrem Ergebnis). Das war zu einfach, so dass Sie es in vielen unterschiedlichen und schwierigen Möglichkeiten:

Hinweis: Die Frage in der FAQ ist nicht meine genaue Frage: Ich bin Zugriff auf die Sammlung nicht über eine Sitzung, aber ich bin Ermöglichen, dass Hibernate eine Auflistung von untergeordneten Entitäten als ein Feld auf dem übergeordneten Element auffüllt. Die Kindersammlung erweitert sich dadurch, dass sie sich ihre Kinder anschließt, um eine Sammlung von Enkelkindern als Feld für das Kind (ihre Eltern) zu bevölkern. Die Ähnlichkeit besteht darin, dass ich das große Linke Join sehe, wenn ich mir das SQL ansehe, das durch den Hibernate erzeugt wird, und dass ich aus den FAQs entnehme, dass Hibernate nicht in Intelligence baktet (wie zum Beispiel die ID-Primärschlüsselannotation auf der Entität) Duplikate (manche Leute wollen es so, sagen sie). Sie sagen auch explizit, dass SET verwendet wird, um Duplikate auf Codeebene herauszufiltern.

+0

Übrigens verstehe ich im Hibernate-Beispiel nicht, warum sie die Duplizierung der Verwendung von Left Outer Joins zuschreiben. ein innerer Join, würde die gleiche Ergebnismenge (5X3 = 15) mit den Duplikaten erzeugen, da es keine baumelnden Tupel von der Order-Relation gibt, was ist der Linkout-Join, der zu den Resultaten über den inneren Join hinzugefügt wird? – naftalimich