2012-11-29 8 views
10

Ich habe eine Reihe von Entitäten, die miteinander verbinden einen Zyklus bilden, dh, Elternteil P hat zwei Eins-zu-viele Beziehungen mit zwei Kind Entitäten C1 und C2 und jeder Eine davon hat eine Eins-zu-viele-Beziehung mit einer anderen Entität A. Entität A realisiert die Zuordnung dieser Entitäten (C1, C2) und definiert die Attribute der Beziehung (es ist nicht nur eine Join-Tabelle). Alle Beziehungen sind in beide Richtungen navigierbar.
domain objects
die folgende Frage ergibt sich aus diesem Entwurf: Was sollte die Kaskadenstrategie sein, so dass Unternehmen A/fusionierten beibehalten werden kann, da Sie immer EntityManager-Operationen auf der Root-Entität P aufrufen? Sollte A von beiden Pfaden erreichbar sein?JPA + Hibernate - Zyklen in Entity-Beziehungen - Cascade-Strategie

Überlegungen: Es scheint, dass, wenn die Anwendung beschließt, nur einen Kaskadenpfad bereitzustellen, Szenarien auftreten können, die eine TransientObjectException auslösen. Wenn es beide Pfade bereitstellt, müssen diese Pfade den vollen Zyklus machen, wie beispielsweise versucht werden könnte, durch C1 gespeichert zu werden.

Versionen: JPA 2.0, Hibernate Core 4.1.7, Hibernate-JPA-2.0-API 1.0 .1

Antwort

3

Ich kann Ihnen meine 2 Cent geben, tut mir leid, wenn meine Antwort ein bisschen lang ist.

Wenn Sie einen Kaskadierungskonflikt dieser Art haben, liegt das möglicherweise daran, dass Ihr Kaskadierungsansatz oder Ihr Domänenmodell nicht gut definiert ist. Ich würde vorsichtig sein, eine Kaskadenstrategie auf einen Gesamtgraphen oder einen nicht verwandten Satz von Elementen zu verallgemeinern.

Mein Ratschlag wäre, dass die Kaskadenstrategie nur auf Datensätzen angewendet werden sollte, die stark miteinander verbunden sind und denselben Typ haben, wie für eine Klasse und ihre (privaten) inneren Klassen in der Java-Welt. Die Beziehung zwischen der Mutterklasse und ihren Kindern sollte ebenfalls exklusiv sein (in UML heißt sie Not-Shared Association).

Natürlich können Sie auch anders (wir können alle faul sein), aber am Ende können Sie ein Netz von Kopplung zwischen Ihrem einzelnen Persistenz-Flow (oder Persistenz-Konfiguration) und Ihrem Geschäftsablauf erstellen. Sie müssen viele Ausnahmen verwalten und eine Menge Konfigurationslogik um die Kaskadenstrategie machen, die Sie zuvor eingestellt haben (speichern, aktualisieren, löschen).

Der extreme Ansatz wäre, dass einige nur ein großes Wurzelobjekt speichern möchten. Warum nicht? der Rest "sollte in Kaskade bleiben". In der Tat könnte dies die Wartbarkeit Ihres Systems ernsthaft einschränken. Außerdem müssen Sie möglicherweise den Status Ihres großen Graphen im Speicher verwalten, wenn Sie ihn laden, speichern und zusammenführen.

Wenn Sie eine Webanwendung oder eine Client-Server-Anwendung ausführen, sollte Ihr Web-Workflow in der Lage sein, bei jeder Anforderung einen begrenzten Satz von Objekten zu speichern, ohne alles aus dem Stammelement speichern zu müssen. Ich weiß, dass ich nicht direkt auf Ihre Frage antworte. Also lassen Sie uns zurück zu Ihrem Beispiel gehen:

Nehmen wir an, P ist eine Bank, und C1 und C2 sind zwei Clients, und A ist ein Produkt.

Ich habe zwei einfache Antworten: 1) Jede Schicht kann separat ohne Kaskadierung gespeichert werden. Aber es kann innerhalb der gleichen Transaktion und in der gleichen DAO oder nicht getan werden, wenn Sie wollen.

2) P und C "kann" kaskadiert werden. Aber A muss in einem anderen Workflow gespeichert werden.

Das erinnert mich an ein Kapitel von Peter Coad, wo er von einer „Domain Driven Analysis“ spricht: http://www.petercoad.com/download/bookpdfs/jmcuch01.pdf

In diesem Kapitel wird erläutert, wie verschiedene Objekte in einem Diagramm kann auf verschiedene Urbilder getrennt werden. Der Persistenzworkflow sollte zwischen Transaktionsdaten und einer Beschreibung oder einem "Ding" nicht identisch sein. Dies kann dazu beitragen, eine bessere Kaskadierungsstrategie zu implementieren:

Ich hoffe, es hilft.

3

Im Allgemeinen ist es eine gute Idee, nur in engen Assoziationen und nur in Parent -> Kind (oder Owner-> besessen) Richtung zu kaskadieren. In Ihrem Fall wäre es wahrscheinlich P->C1 und P->C2. Da A kein offensichtliches Elternteil hat, sollte es separat gespeichert werden. Dies kann als @etienno in Ihrem DAO in einer einzigen Transaktion zusammen mit P (und C1, C2) erwähnt erfolgen. Ich kenne Ihr Domain-Modell nicht, aber vielleicht ist sogar A auf konzeptioneller Ebene eine separate Entität, in welchem ​​Fall eine separate Speicherung noch mehr gerechtfertigt ist.

Cascading zu vielen Objekten, die nicht eng verwandt sind, kann auf lange Sicht den gesamten Graphen, wenn es größer wird, nicht handhabbar machen.

In Situationen wie diesem ist es immer gut die Frage zu stellen "Wie würdest du es ohne Hibernate machen". In Ihrem Fall würden Sie wahrscheinlich zunächst P, dann C1, C2 und dann A speichern. AFAIK JPA/Hibernate bietet keine explizite Möglichkeit, eine solche Bestellung durchzusetzen. Daher müssen einige Dinge manuell von Ihnen erledigt werden.