Spring-JPA: Update der übergeordneten Entität ausfällt andauern neue untergeordnete Entitäten, interpretieren Sie als Transient statt
Ich bin neu in Spring/JPA/Hibernate, und während es klingt einfach, die Realität einfach noch nicht. Ich könnte etwas Hilfe gebrauchen.
Habe ich eine übergeordnete Entität, die über eine Liste von Kind-Entitäten. Ich werde diese verwenden, um halten Sie die Diskussion einfach:
@Entity
public class Parent {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Long id;
@OneToMany(fetch=FetchType.EAGER, cascade = CascadeType.ALL, mappedBy="parent")
private List<Child> children= new ArrayList<Child>();
etc...
}
@Entity
public class Child {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Long id;
@ManyToOne
private Parent parent;
etc...
}
@Repository
public interface ParentRepository extends JpaRepository<Parent, Long> {};
Runde 1, ich erstelle ein neues Elternteil und einem neuen Kind, fügen Sie die Kind, um die Eltern-Liste und der Eltern auf das Kind. Wenn ich die Eltern das Kind ebenfalls gespeichert.
@Transactional(propagation=Propagation.REQUIRES_NEW)
void create() {
Parent parent = new Parent();
Child child = new Child();
parent.add(child);
child.setParent(parent);
parent = repository.save(parent);
}
Nun Runde 2, ich füge ein neues Kind:
@Transactional(propagation=Propagation.REQUIRES_NEW)
void update() {
Parent parent = repository.findOne(parentID);
Child newChild = new Child();
newChild.setParent(parent);
parent.add(newChild);
parent = repository.save(parent);
}
Aber dieses mal ist die neue Kind ist nie beibehalten!
Ich habe versucht, die meisten jede Art von CascadeType, @GeneratedValue GenerationType, @Transactional Vermehrung geben...
Tracing dies durch hibernate (schmerzhaft!), hier ist, was ich gefunden habe:
- Beim speichern das zweite mal, das problem ist mit dem zweiten (neuen) Kindes.
- Das Problem scheint zu sein, dass, wenn es darum geht, Zeit zu bestehen, den Eltern die Child-Liste
das neue Kind ist nicht in der EntityManager (noch) und damit als Vorübergehend. - Als Ergebnis, es ist tatsächlich überliefert worden sein, die Kette als null, was im folgenden:
org.springframework.transaction.TransactionSystemException: Could not commit JPA transaction; nested exception is javax.persistence.RollbackException: Error while committing thetransaction at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:521) ... Caused by: javax.persistence.RollbackException: Error while committing the transaction at org.hibernate.ejb.TransactionImpl.commit(TransactionImpl.java:92) at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:512) ... Caused by: org.hibernate.AssertionFailure: collection [null] was not processed by flush() at org.hibernate.engine.spi.CollectionEntry.postFlush(CollectionEntry.java:225) ...
- Es relevant sein könnte, dass in meinem eigentlichen code "Kind" hat auch eine Karte von Kind-Entitäten. Dieser "Wert" ist, was wird weitergegeben als null aufgrund der "Vorübergehende" Zweckentfremdung.
- Ich habe mit repository.saveAndFlush (), um die Dinge synchron zum Debuggen. Wenn ich nur .save() my @PreUpdate EntityListener heißt aber @PostUpdate Hörer nie.
- Es scheint, dass es kein problem wäre, wenn das Kind wurden nur beibehalten oder eine Id-zumindest vor dem fortbestehen Eltern. Aber es scheint auch kontraproduktiv, um dies manuell tun. Noch, das ist die einzige alternative die ich mir denken kann.
Vielen Dank für das Lesen. Jede Hilfe wäre sehr geschätzt werden!
- Leider sehen wir nicht in Ihrer stacktrace, die Sammlung ist null. Könnte es sein, dass die Karte nicht initialiezed in Ihrem Kind? Sie könnten versuchen, weisen Sie eine neue hashmap zu den Feld-Attribut direkt zu testen, ob es behebt den Fehler? Hibernate hat einige Macken mit genullt, Sammlungen. Versuchen Sie, um sicherzustellen, dass die Sammlungen nicht null und wiederholen Sie Ihren test.
- Danke für Antworten, Martin. Die null ist das Kind, das Kind. In der Objekt-es ist eine Karte, die Objekte, die Sie in es. Allerdings, wenn die Eltern beibehalten wird, Hibernate sieht das Kind, nicht sehen es in der EntityManager, der entscheidet, Sie muss vorübergehend sein und so nur setzt seinen Wert auf null (in einer Identitäts-Karte, nicht auf das original-Objekt). Funktioniert Hibernate haben ein Problem mit den Karten im besonderen?
- Hibernate habe ein Problem mit Sammlungen wäre zu viel zu sagen. Aber Sammlungen kann schwierig sein zu behandeln. Wir lief in einige Probleme mit orphan removal (=true), wenn wir ersetzt einige Sammlungen komplett. Zum Glück für uns, diese Dinge werden normalerweise beschrieben durch die Menschen und die Dokumentation sehr gut und wir lösen es schnell, sobald Sie wissen, was Sie suchen. Grundsätzlich sollte man nicht erneut initialisieren, Sammlungen, sobald Sie einmal vorhanden, aber mit klarem statt. Deshalb hatte ich diese Idee für dein problem. Das einfachste könnte sein, erstellen Sie einen Testfall mit A, B und C und führen Sie ihn, um Ihr problem.
- Aye. Nicht sehen, Sie löste es bereits. Also vergiss meinen Kommentar oben über den testcase -:) ist Es wahr, dass Sie keine änderungen machen / Abfragen in eine entitylistener. Ich denke nicht, dass es schlechte Praxis (ak-db-trigger), aber es kann schwierig sein zu Steuern. Hauptproblem ist hier, dass die ActionQueue von Hibernate ist schon gebaut oder wird in der Bauphase.
- Auf der anderen Seite Envers tut genau dies, aber Sie verwalten die zusätzliche Arbeit, die in so genannten Arbeiter befestigt, um die beforetransaction complete-Ereignis. Anstatt die änderungen direkt Sie einen anderen bauen, der ActionQueue verarbeitet werden. Gebaut haben wir eine E-Mail-system die gleiche Weise wie envers und läuft als erwartet.
- Ich würde angeschaut Envers eine Weile zurück. Es sah perfekt aus, außer wir haben einige spezielle Bedürfnisse, die gebaut werden müssen sowieso. Trotzdem, es sah schön.
Du musst angemeldet sein, um einen Kommentar abzugeben.
Alles, was Sie gezeigt haben, scheint ziemlich normal, also das problem liegen könnte, dass die Karte, die Sie erwähnt. Ich habe eine Beispiel für eine bidirektionale eins-zu-viele mit Spring Data JPA auf Github. Sie können den code oder Klonen und starten Sie es mit:
Habe das problem gefunden, obwohl ich nicht wirklich haben eine komplette Lösung noch nicht.
Zunächst einige zusätzliche hintergrund. Neben Elternteil und Kind, ich hatte eine Verwandte Klasse nenne ich "Haus" hier. Haus hat eine EntityListener so definiert, dass, wenn es gespeichert/aktualisiert werden, werden die zugehörigen Eltern & Kind-Objekte erstellt/aktualisiert. So ist es bei House PostPersist/PostUpdate, dass Eltern-und Kind-Objekte erzeugt, verknüpft, deutete zurück zum Haus, und dann beibehalten.
So, das problem scheint zu sein, das wird gemacht, bevor das Haus Transaktion abgeschlossen ist. Lediglich durch herausziehen des Eltern/Kind-Aktivität, bis nach dem Haus Aktivität abgeschlossen ist, alle Probleme waren Weg.
Das einzige, was ich kann herausfinden (ich werde ein wenig tiefer Graben) ist, dass da Haus noch nicht vollständig persistiert in diesem moment, es Ergebnisse in den Transienten Zustand wie oben beschrieben.
Update:
Kreide bis zu Ignoranz. Offenbar EntityCallback Methoden "sollte das nicht nennen EntityManager oder Query-Methoden und sollten nicht den Zugriff auf andere entity-Objekte." Wusste nicht, dass. Dies wirft nun die Frage, wie sollte ich auslösen eines Unternehmens-Erstellung auf eine andere Tätigkeit. Aber ich werde einen weiteren thread starten, für, dass, wenn notwendig. Vielen Dank an alle!