2009-06-30 6 views
69

Ich habe versucht, Hibernate's inverse Attribut zu verstehen, und es scheint nur eines dieser Dinge zu sein, die konzeptionell schwierig ist.Wann sollte inverse = false für NHibernate/Hibernate OneToMany-Beziehungen verwendet werden?

Der Kern, die ich erhalte, ist, dass, wenn Sie eine übergeordnete Einheit (zB Eltern) haben, die eine Sammlung von Child-Objekte mit einem one-to-many Mapping hat, inverse Einstellung auf dem Mapping = true Hibernate sagt, dass ' Die andere Seite (das Kind) ist dafür verantwortlich, sich selbst zu aktualisieren, um die Fremdschlüsselreferenz in ihrer Tabelle beizubehalten.

Dies hat zwei Vorteile, wenn es darum geht, Children der Sammlung in Ihrem Code hinzuzufügen und dann das Parent (mit Kaskaden-All-Set) zu speichern: you save an unneccessary hit on the database (weil Hibernate ohne Inversersatz denkt, dass es zwei Stellen hat die FK Beziehung zu aktualisieren), und nach den offiziellen Dokumenten:

Wenn die Spalte einer Vereinigung deklariert wird NOT NULL, NHibernate verursachen kann Verletzungen Einschränkung, wenn es schafft oder aktualisiert die Vereinigung. Um dieses Problem zu verhindern, müssen Sie eine bidirektionale Verbindung mit dem vielwertigen Ende (der Satz oder Tasche) als inverse = "true" markiert verwenden.

Das scheint alles bisher Sinn zu machen. Was ich nicht verstehe, ist folgendes: Wann würden Sie NICHT inverse = true für eine Eins-zu-viele-Beziehung verwenden wollen?

Antwort

81

Wie Matthieu sagt, ist der einzige Fall, in dem Sie inverse = true nicht setzen möchten, wenn es nicht sinnvoll ist, dass das Kind selbst für die Aktualisierung verantwortlich ist, z. B. wenn das Kind keine Kenntnis hat von seinem Elternteil.

Werfen sich eine reale Welt versuchen, und schon gar nicht erfundenes Beispiel:

<class name="SpyMaster" table="SpyMaster" lazy="true"> 
    <id name="Id"> 
    <generator class="identity"/> 
    </id> 
    <property name="Name"/> 
    <set name="Spies" table="Spy" cascade="save-update"> 
    <key column="SpyMasterId"/> 
    <one-to-many class="Spy"/> 
    </set> 
</class> 

<class name="Spy" table="Spy" lazy="true"> 
    <id name="Id"> 
    <generator class="identity"/> 
    </id> 
    <property name="Name"/> 
</class> 

Spymasters können Spione, aber Spione nie wissen, wer ihre spymaster sind, weil wir nicht den Viele-zu-Eins-Beziehung enthalten sind, in der Spionageklasse. Außerdem kann ein Spion (bequemerweise) Schurke werden und muss daher nicht mit einem Spionagemeister in Verbindung gebracht werden. Wir können Entitäten wie folgt erstellen:

var sm = new SpyMaster 
{ 
    Name = "Head of Operation Treadstone" 
}; 
sm.Spies.Add(new Spy 
{ 
    Name = "Bourne", 
    //SpyMaster = sm // Can't do this 
}); 
session.Save(sm); 

In einem solchen Fall, dass Sie die FK Spalte Nullwerte enthalten sein gesetzt würde, weil der Akt sm des Sparens in die Spymaster Tabelle einfügen würde und der Spy-Tabelle und erst danach würde es Aktualisieren Sie dann die Spionage-Tabelle, um den FK festzulegen. Wenn wir in diesem Fall inverse = true setzen würden, würde der FK niemals aktualisiert werden.

+0

Das hat nicht für mich funktioniert. Es führt das Update nie aus. Es fügt nur sie ein. – BradLaney

14

Wenn Sie eine unidirektionale Zuordnung haben möchten, d. H. Dass die Kinder nicht zum übergeordneten Element navigieren können. Wenn dies der Fall ist, sollte die FK-Spalte NULLABLE sein, da die untergeordneten Elemente vor dem übergeordneten Element gespeichert werden.

28

Trotz der gut angenommenen Antwort habe ich eine andere Antwort darauf.

Betrachten wir ein Klassendiagramm mit diesen Beziehungen:

 
Parent => list of Items 
Item => Parent 

Niemand jemals sagte, dass das Item => Eltern bezogen auf die Parent => Produkte Beziehung redundant ist. Ein Artikel könnte auf ein Elternteil verweisen.

Aber in Ihrer Anwendung, wissen Sie, dass die Beziehungen redundant sind. Sie wissen, dass die Beziehungen nicht separat in der Datenbank gespeichert werden müssen. Sie entscheiden sich also dafür, es in einem einzigen Fremdschlüssel zu speichern, der vom Artikel zum Elternteil zeigt. Diese minimale Information reicht aus, um die Liste und die Referenz zurück zu bauen.

Alles, was Sie tun müssen, dies mit NH zur Karte ist:

  • die gleiche Fremdschlüssel für beide
  • Beziehungen verwenden
  • NH sagen, dass man (die Liste) zum anderen redundant ist und ignoriert werden konnte beim Speichern des Objekts. (Das ist, was NH tatsächlich mit inverse="true" tut)

Dies sind die Gedanken, die für inverse relevant sind. Nichts anderes. Es ist keine Wahl, es gibt nur eine Möglichkeit zur korrekten Zuordnung.


Der Spion Problem: Es ist eine ganz andere Diskussion wenn Sie eine Referenz aus dem Artikel an die Eltern unterstützen wollen. Das liegt an Ihrem Geschäftsmodell, NH trifft hier keine Entscheidungen. Wenn eine der Relationen fehlt, gibt es natürlich keine Redundanz und keine Inverse.

Missbrauch: Wenn Sie inverse = "true" auf einer Liste verwenden, die keine Redundanz im Speicher hat, wird sie einfach nicht gespeichert. Wenn Sie inverse = "true" nicht angeben, wenn es da sein soll, kann NH die redundanten Informationen zweimal speichern.

+0

Ich fand diese Antwort besser verständlich als die angenommene Antwort – r3try

+0

Viel einfacher und auf den Punkt als meine [Antwort] (http://Stackoverflow.com/a/6951546/221708). –

Verwandte Themen