Hibernate kann nicht gleichzeitig mehrere Beutel holen
-
30-09-2019 - |
Frage
Hibernate wirft diese Ausnahme bei der Session Erstellung:
org.hibernate.loader.MultipleBagFetchException: können nicht gleichzeitig mehrere Beutel holen
Das ist mein Testfall:
Parent.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<Child> children;
}
Child.java
@Entity
public Child {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Long id;
@ManyToOne
private Parent parent;
}
Wie wäre es dieses Problem? Was kann ich tun?
Bearbeiten
OK, das Problem, das ich habe, ist, dass ein andere „Eltern“ Einheit in meinen Eltern, mein reales Verhalten ist dies:
Parent.java
@Entity
public Parent {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Long id;
@ManyToOne
private AntoherParent anotherParent;
@OneToMany(mappedBy="parent", fetch=FetchType.EAGER)
private List<Child> children;
}
AnotherParent.java
@Entity
public AntoherParent {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Long id;
@OneToMany(mappedBy="parent", fetch=FetchType.EAGER)
private List<AnotherChild> anotherChildren;
}
Ruhezustand nicht wie zwei Sammlungen mit FetchType.EAGER
, aber dies scheint ein Fehler zu sein, ich bin nicht ungewöhnlich, Dinge zu tun ...
Entfernen von FetchType.EAGER
von Parent
oder AnotherParent
löst das Problem, aber ich brauche es, so wirkliche Lösung ist @LazyCollection(LazyCollectionOption.FALSE)
zu verwenden, anstatt FetchType
(dank Bozho für die Lösung).
Lösung
Ich denke, eine neuere Version von Hibernate (mit Unterstützung für JPA 2.0) damit umgehen soll. Aber sonst kann man es umgehen, indem sie die Sammlung Felder mit Anmerkungen versehen mit:
@LazyCollection(LazyCollectionOption.FALSE)
Denken Sie daran, das fetchType
Attribut aus der @*ToMany
Anmerkung zu entfernen.
Aber beachten Sie, dass in den meisten Fällen eine Set<Child>
ist besser geeignet als List<Child>
, so dass, wenn Sie wirklich ein List
brauchen - go für Set
Andere Tipps
Einfach von List
Typ Set
Typ verändern.
Fügen Sie eine Hibernate spezifische @Fetch Anmerkung zu Ihrem Code:
@OneToMany(mappedBy="parent", fetch=FetchType.EAGER)
@Fetch(value = FetchMode.SUBSELECT)
private List<Child> childs;
Dies sollte das Problem beheben, zu Hibernate Fehler im Zusammenhang HHH-1718
Nach dem mit jeder einzelnen Option versuchen, in diesen Beiträgen und andere beschreiben, kam ich zu dem Schluss, dass die das Update ist wie folgt.
In jedem XToMany Ort @XXXToMany(mappedBy="parent", fetch=FetchType.EAGER)
und zwischen nach
@Fetch(value = FetchMode.SUBSELECT)
Das ist für mich gearbeitet
Um es zu beheben einfach Set
anstelle von List
für verschachteltes Objekt nehmen.
@OneToMany
Set<Your_object> objectList;
und vergessen Sie nicht fetch=FetchType.EAGER
es wird funktionieren.
Es gibt ein weiteres Konzept CollectionId
in dem Ruhezustand, wenn Sie mit der Liste halten wollen.
fand ich eine gute Blog-Post über das Verhalten von Hibernate in dieser Art von Objekt-Zuordnungen: http : //blog.eyallupu.com/2010/06/hibernate-exception-simultaneously.html
Sie können Stand EAGER Listen in JPA halten und mindestens einer von ihnen die JPA-Annotation hinzufügen @OrderColumn (mit offensichtlich den Namen eines Feldes zu bestellen). Keine Notwendigkeit spezifischer Hibernate Annotations. Aber bedenken Sie könnte es leere Elemente in der Liste erstellen, wenn das gewählte Feld ab 0 keine Werte haben
[...]
@OneToMany(mappedBy="parent", fetch=FetchType.EAGER)
@OrderColumn(name="orderIndex")
private List<Child> children;
[...]
bei Kindern dann sollten Sie das orderIndex Feld hinzufügen
Der Grund, warum Sie diese Ausnahme erhalten, dass Hibernate ein Kartesisches Produkt würde am Ende zu tun, die für die Leistung schlecht ist.
Nun, obwohl Sie könnten „fix“ das Problem durch Set
statt List
verwenden, sollten Sie das nicht tun, weil das Kartesisches Produkt wird nach wie vor in den zugrunde liegenden SQL-Anweisungen sehen sein.
Sie sind besser dran, da eifrig Abruf von FetchType.EAGER
zu Fetchype.LAZY
Schalt ist ein schreckliche Idee, die kritische Anwendung Performance-Probleme führen kann.
Wenn Sie die untergeordneten Entitäten über eine Multi-Level-Hierarchie zu holen, wählen Sie besser aus dem am weitesten innen Kind bis zu den Eltern, wie in diesem Artikel erläutert.
Wenn Sie zu komplexe Objekte mit saveral Sammlung nicht gute Idee sein könnte, alle mit EAGER fetchType, eine bessere Nutzung LAZY und haben, wenn Sie wirklich die Sammlungen verwenden laden müssen. Hibernate.initialize(parent.child)
die Daten zu holen
Wir haben versucht, Set statt Liste , und es ist ein Alptraum: Wenn Sie zwei neue Objekte hinzufügen, gleich () und hashCode () fehlschlagen, beide zu unterscheiden! Denn sie haben keine ID.
typische Werkzeuge wie Eclipse erzeugen diese Art von Code aus Datenbanktabellen:
@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 ein href lesen <= "http://www.onjava.com/pub/a/onjava/2006/09/13/dont-let-hibernate-steal-your-identity.html?page= 1" rel = "nofollow noreferrer"> dieser Artikel , die richtig, wie verkorkst JPA / Hibernate erklärt wird. Nach der Lektüre dieses, ich denke, das ist das letzte Mal ich jede ORM in meinem Leben verwenden.
Ich habe auch Jungs Domain Driven Design Begegnung, die im Grunde sagt ORM ist eine schreckliche Sache.
Für mich ist das Problem verschachtelt wurde zu haben EAGER abruft.
Eine Lösung ist, die verschachtelten Felder auf LAZY und verwendet Hibernate.initialize (), um das verschachtelte Feld zu laden (s):
x = session.get(ClassName.class, id);
Hibernate.initialize(x.getNestedField());
Sie könnten eine neue Annotation verwenden diese zu lösen:
@XXXToXXX(targetEntity = XXXX.class, fetch = FetchType.LAZY)
In der Tat, holt den Standardwert ist FetchType.LAZY zu.