So vermeiden Sie NHibernate.NonUniqueObjectException

8

Ich schreibe eine Blog-Engine als Lernübung. Ich weiß, es gibt viele Blog-Engines da draußen, aber ertragen Sie mit mir ...

Ich habe eine BlogPost-Entität mit einer Eigenschaft Tags, bei der es sich um eine IList der zugeordneten Tags handelt. Die Methode BlogPost.SetTags (string) teilt die Zeichenfolge auf, erstellt neue Tag-Objekte mit dem angegebenen Tag-Namen und fügt sie der Liste hinzu. Gleiches für BlogPost.AddTag (string tagName).

Was ich gerne geschehen würde, ist, dass wenn ich BlogPost.AddTag ("foo") anrufe, wo eine Tag Entity namens "foo" bereits existiert und in der Datenbank persistiert, realisiert nHibernate das und verbindet den Post mit das vorhandene Tag

In der BlogRepository.Save () -Methode überprüfe ich, ob jedes Tag in der Liste Tags bereits existiert. Wenn nicht, speichere ich es mit einem Aufruf von TagRepository.Save (tag);

Das Problem ist, in dem folgenden Beispielcode erhalte ich einen Fehler "NHibernate.NonUniqueObjectException: ein anderes Objekt mit demselben Bezeichner-Wert war bereits der Sitzung zugeordnet: Tag 1, der Einheit: CMS.Core.Model .Tag ", wenn ich versuche, ein BlogPost-Objekt mit einem vorhandenen Tag zu speichern. Wenn ich ein BlogPost-Objekt behalte, das nur neue Tags verwendet, werden diese erstellt und alles ist in Ordnung.

Hinweis: Ich verwende auch den TagName als Primärschlüssel in der Datenbank für die Tabelle bp_Tags. Es erschien überflüssig, eine Ganzzahl oder eine GUID-PK zu verwenden, wenn die Tabelle nur eindeutige Tag-Namen speichert.

Meine nHibernate-Konfiguration sieht folgendermaßen aus:

%Vor%

NHibernate.NonUniqueObjectException: Ein anderes Objekt mit demselben Bezeichner-Wert war bereits der Sitzung zugeordnet: Tag 1, der Entität: Bariliant.CMS.Core.Model.Tag

%Vor%

...

Irgendwelche Gedanken darüber, was ich falsch mache und wie ich es beheben kann?

    
Jason Barile 11.11.2009, 05:13
quelle

2 Antworten

8

Da TagName die ID ist, wird die Identity Map von NHibernate angezeigt. Seine Identitätskarte kennt bereits ein Objekt mit derselben ID, daher gibt es diese Ausnahme.

Vielleicht möchten Sie etwas ausprobieren, bei dem Sie nachsehen, ob dieses Tag bereits in dieser Sitzung vorhanden ist, und wenn ja, dann verbinden Sie dieses bereits bestehende Tag mit dem zweiten Beitrag.

Pseudocode Beispiel:

%Vor%

Dieser Blogeintrag gibt Ihnen eine detaillierte Erklärung: NHibernate - Übergreifende Sitzungen

    
Daniel Auger 12.11.2009, 00:53
quelle
4

Die Art, wie Sie vorgehen, ist nicht die Art, wie ich es tun würde, aber hier ist, wie Sie Ihr Problem lösen können. Normalerweise sind in der objektorientierten Programmierung die folgenden 2 Objekte NICHT gleich:

%Vor%

Sie haben zwei separate Objekte mit identischem Status erstellt, aber sie sind zwei verschiedene Objekte. Wenn Sie sie also nach Gleichheit vergleichen, sind sie nicht identisch. Wenn es um NHibernate geht, sind diese Objekte eindeutig die gleiche Entität.

Wir lösen dies für NHibernate durch Überschreiben von 2 Methoden der Objektklasse. GetHashCode () und Equals ()

GetHashCode () gibt grundsätzlich einen eindeutigen Hashcode basierend auf dem Status eines Objekts zurück. Equals () vergleicht zwei Objekte für die Gleichheit

so:

%Vor%

Grundsätzlich verknüpft GetHashCode den Objekttyp und den Namen des Tags als String, zB App.Domain.Tag|nameoftag und generiert einen Hashcode für diese Zeichenfolge

Equals () vergleicht dann das GetHashCode () - Ergebnis für das erste Objekt mit dem GetHashCode () - Ergebnis, damit das zweite Objekt auf Gleichheit testet. Wenn Sie dies mit den beiden oben definierten Objekten tun, sind die beiden Hashcodes identisch und daher ist der Vergleich für Equals () wahr. Wenn NHibernate die beiden Objekte auf Gleichheit in ihren Innenfunktionen testet, stellt es fest, dass sie identisch sind und es sollte Ihr Problem lösen.

    
reach4thelasers 12.11.2009 00:21
quelle

Tags und Links