Hibernate kann nicht gleichzeitig mehrere Taschen holen

Hibernate triggers diese Ausnahme während der Erstellung von SessionFactory aus:

org.hibernate.loader.MultipleBagFetchException: kann nicht gleichzeitig mehrere Taschen abrufen

Das ist mein Testfall:

Eltern.java

@Entity public Parent { @Id @GeneratedValue(strategy=GenerationType.IDENTITY) private Long id; @OneToMany(mappedBy="parent", fetch=FetchType.EAGER) // @IndexColumn(name="INDEX_COL") if I had this the problem solve but I retrieve more children than I have, one child is null. private List children; } 

Kind.java

 @Entity public Child { @Id @GeneratedValue(strategy=GenerationType.IDENTITY) private Long id; @ManyToOne private Parent parent; } 

Wie wäre es mit diesem Problem? Was kann ich tun?


BEARBEITEN

OK, das Problem, das ich habe, ist, dass eine andere “Eltern” -Entität in meinem Elternteil ist, mein wirkliches Verhalten ist das:

Eltern.java

 @Entity public Parent { @Id @GeneratedValue(strategy=GenerationType.IDENTITY) private Long id; @ManyToOne private AntoherParent anotherParent; @OneToMany(mappedBy="parent", fetch=FetchType.EAGER) private List children; } 

AnotherParent.java

 @Entity public AntoherParent { @Id @GeneratedValue(strategy=GenerationType.IDENTITY) private Long id; @OneToMany(mappedBy="parent", fetch=FetchType.EAGER) private List anotherChildren; } 

Hibernate mag keine zwei Sammlungen mit FetchType.EAGER , aber das scheint ein Fehler zu sein, ich mache keine ungewöhnlichen Dinge …

Entfernen von FetchType.EAGER von Parent oder AnotherParent triggers das Problem, aber ich brauche es, so echte Lösung ist die Verwendung von @LazyCollection(LazyCollectionOption.FALSE) anstelle von FetchType (Dank Bozho für die Lösung).

Ich denke, dass eine neuere Version von Hibernate (unterstützt JPA 2.0) dies behandeln sollte. Aber ansonsten können Sie es umgehen, indem Sie die Sammlungsfelder mit folgenden Anmerkungen versehen:

 @LazyCollection(LazyCollectionOption.FALSE) 

Denken Sie daran, das fetchType Attribut aus der @*ToMany Annotation zu entfernen.

Beachten Sie jedoch, dass in den meisten Fällen ein Set besser geeignet ist als das List . Wenn Sie also wirklich keine List benötigen, gehen Sie zu Set

Wechseln Sie einfach vom List zum Set Typ.

Alternativ fügen Sie Ihrem Code eine Hibernate-spezifische @ Fetch-Annotation hinzu:

 @OneToMany(mappedBy="parent", fetch=FetchType.EAGER) @Fetch(value = FetchMode.SUBSELECT) private List childs; 

Dies sollte das Problem im Zusammenhang mit dem Hibernate-Fehler HHH-1718 beheben

Nachdem ich mit jeder einzelnen Option versucht habe, in diesen Posts und anderen zu beschreiben, kam ich zu dem Schluss, dass der Fix ein folgt.

In jedem XToMany Platz @ XXXToMany(mappedBy="parent", fetch=FetchType.EAGER) und dazwischen nach

 @Fetch(value = FetchMode.SUBSELECT) 

Das hat für mich funktioniert

Um es zu beheben, nehmen Sie Set anstelle von List für Ihr verschachteltes Objekt.

 @OneToMany Set objectList; 

und vergessen Sie nicht, fetch=FetchType.EAGER

es wird klappen.

Es gibt ein weiteres Konzept CollectionId in Hibernate, wenn Sie nur mit der Liste bleiben möchten.

Ich habe einen guten Blogbeitrag über das Verhalten von Hibernate in dieser Art von Objektzuordnungen gefunden: http://blog.eyallupu.com/2010/06/hibernate-exception-simultanously.html

Sie können Stand-EAGER-Listen in JPA behalten und zu mindestens einem von ihnen die JPA-Annotation @OrderColumn hinzufügen (mit offensichtlich dem Namen eines zu bestellenden Feldes). Keine Notwendigkeit für spezielle Hibernate-Annotationen. Beachten Sie jedoch, dass leere Elemente in der Liste erstellt werden können, wenn das ausgewählte Feld keine Werte von 0 hat

  [...] @OneToMany(mappedBy="parent", fetch=FetchType.EAGER) @OrderColumn(name="orderIndex") private List children; [...] 

In Children sollten Sie dann das Feld orderIndex hinzufügen

Der Grund, warum Sie diese Ausnahme erhalten, ist, dass Hibernate am Ende ein kartesisches Produkt erstellt, das schlecht für die performance ist.

Obwohl Sie das Problem mit ” Set anstelle von ” List ” beheben konnten, sollten Sie dies nicht tun, da das kartesische Produkt immer noch in den zugrunde liegenden SQL-statementen enthalten ist.

Sie sollten besser von FetchType.EAGER zu Fetchype.LAZY da das Eager-Holen eine schreckliche Idee ist, die zu kritischen Anwendungsleistungsproblemen führen kann .

Wenn Sie die untergeordneten Entitäten über eine Hierarchie mit mehreren Ebenen abrufen müssen, wählen Sie besser aus dem untersten untergeordneten Element bis zu den übergeordneten Elementen aus, wie in diesem Artikel erläutert .

Wenn Sie zu komplexe Objekte mit einer saveralen Sammlung haben, sollten Sie nicht alle mit EAGER fetchType verwenden. Verwenden Sie besser LAZY und wenn Sie die Sammlungen wirklich laden müssen, verwenden Sie: Hibernate.initialize(parent.child) , um die Daten abzurufen.

Wir haben Set anstelle von List ausprobiert und es ist ein Alptraum: Wenn Sie zwei neue Objekte hinzufügen, können equals () und hashCode () beide nicht unterscheiden! Weil sie keine ID haben.

Typische Tools wie Eclipse generieren diese Art von Code aus databasetabellen:

 @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((id == null) ? 0 : id.hashCode()); return result; } 

Sie können auch diesen Artikel lesen, der richtig erklärt, wie gefickt JPA / Hibernate ist. Nachdem ich dies gelesen habe, denke ich, dass dies das letzte Mal ist, dass ich irgendein ORM in meinem Leben benutze.

Ich bin auch auf Domain Driven Design-Typen gestoßen, die grundsätzlich sagen, ORM sei eine schreckliche Sache.

Sie könnten eine neue Anmerkung verwenden, um dies zu lösen:

 @XXXToXXX(targetEntity = XXXX.class, fetch = FetchType.LAZY) 

Tatsächlich ist der Standardwert von fetch auch FetchType.LAZY.