Werden NhiberNate Icriiteria -Abfragen zwischengespeichert oder in die Identitätskarte eingesetzt?

StackOverflow https://stackoverflow.com/questions/4829674

Frage

Mit NhiberNate stelle ich normalerweise nach einzelnen Datensätzen mit den Methoden GET () oder load () ab (je nachdem, ob ich einen Proxy benötige oder nicht):

SomeEntity obj = session.Get<SomeEntity>(new PrimaryKeyId(1));

Wenn ich diese Aussage zweimal ausführe, wie das Beispiel unten, sehe ich nur eine Abfrage in meinen unittesten Ausführungen:

SomeEntity obj1 = session.Get<SomeEntity>(new PrimaryKeyId(1));
SomeEntity obj2 = session.Get<SomeEntity>(new PrimaryKeyId(1));

So weit, ist es gut. Aber ich bemerkte ein seltsames Verhalten, als ich das gleiche Objekt mit einer Icriiteria -Abfrage erhielt. Schauen Sie sich meinen Code unten an: Ich erhalte die erste Objektinstanz. Ich ändere dann den Wert einer Eigenschaft auf 10 (der Wert in der Datenbank beträgt 8), holen Sie sich eine andere Instanz und überprüfen Sie schließlich die Werte der zweiten Objektinstanz.

//get the first object instance.
SomeEntity obj1 = session.CreateCriteria(typeof(SomeEntity))
                         .Add(Restrictions.Eq("Id", new PrimaryKeyId(1)))
                         .UniqueResult<SomeEntity>();

//the value in the database and the property is 8 at this point. Let's set it to 10.
obj1.SomeValue = 10;

//get the second object instance.
SomeEntity obj2 = session.CreateCriteria(typeof(SomeEntity))
                         .Add(Restrictions.Eq("Id", new PrimaryKeyId(1)))
                         .UniqueResult<SomeEntity>();

//check if the values match.
Assert.AreEqual(8, obj2.SomeValue);

Aus irgendeinem Grund schlägt die Behauptung fehl, da der Wert 10 von OBJ2 beträgt, obwohl ich mit einer neuen Abfrage nach dem Objekt gefragt habe. Das Lustige ist, dass 2 genau die gleichen ausgewählten Abfragen gemäß meinem Fenster "Unit -Test Ausgabe" ausgeführt werden. Meine Frage: Warum werden 2 Abfragen ausgeführt, wenn das zweite Objekt aus dem ersten Level -Cache abgerufen wird?

Vermisse ich etwas oder ist das ein Fehler?

Grüße, Ted

Bearbeiten Nr. 1: Verwenden von NhiberNate v2.1.2GA Bearbeiten #2: Ich habe einige zusätzliche Erläuterungen zu den 2 Abfragen hinzugefügt, die in den letzten Absatz ausgeführt werden.

War es hilfreich?

Lösung 2

Nachdem ich viel mehr über NhisperNate gelernt habe, kann ich diese Frage jetzt selbst beantworten: Die Icriteria -Abfrage gibt eine Liste von Objekten zurück, die von Nhibernate abgerufen wurden. Nhibernate weiß nicht, welche Objekte zurückgegeben werden, bis sie einzeln mit dem Objekt im Cache der ersten Ebene übereinstimmen. Wenn sich das Element bereits in der Cache -Karte der ersten Ebene befindet, wird das aus der Datenbank gelesene Element verworfen. Wenn es nicht in der Identitätskarte ist, wird das Element in den Cache "Erststufe" eingerichtet.

Ein weiterer "a-ha!" Moment: Angenommen, Sie führen die Abfrage zum ersten Mal aus, während 5 Zeilen in der Datenbank vorhanden sind. Alle Zeilen werden abgerufen und in einen Cache in der ersten Ebene gesteckt. Jetzt werden im Laufe der Zeit 5 weitere Datensätze zur Tabelle hinzugefügt und Sie die Abfrage erneut ausführen. Jetzt sind alle 10 Datensätze abgerufen, aber NhiberNate sieht, dass 5 von ihnen bereits im Cache sind und nur die 5 letzteren Datensätze hinzufügen. Im Grunde genommen haben Sie 5 Datensätze für nichts abgerufen (nur um den Kennungen mit den Objektkennungen in der Identitätskarte abzustimmen).

Andere Tipps

GET/LADEN Verwenden Sie den Cache der 1. Ebene. Deshalb sehen Sie den 2. Ruf die DB nicht. Abfragen verwenden den Cache der 1. Ebene nicht. Sie können jedoch Fragen einrichten, um den Cache der 2. Ebene zu verwenden. Siehe Einzelheiten hier

AKTUALISIEREN Was wahrscheinlich passiert, ist, dass die Abfrage eine 2 -Phasen -Last ausführt. Daher wird das Ergebnissatz erhalten, aber auch den Cache der 1. Ebene überprüft, um festzustellen, ob dort Entitäten existieren. Wenn dies der Fall ist, gibt es das zwischengespeicherte Objekt zurück. Sehen NHibernate.Loader.Loader.GetRow Methode. Hier ist die entsprechende Zeile:

//If the object is already loaded, return the loaded one
obj = session.GetEntityUsingInterceptor(key);

Afaik, nur 'Get' (und vielleicht Load) Verwenden Sie den Cache der 1. Ebene.

Die Verwendung der Kriterien -API führt immer dazu, dass eine Abfrage auf die DB getroffen wird, es sei denn, der Cache der 2. Ebene ist aktiviert.

Bearbeiten: Weitere Informationen finden Sie hier

Ich bin mir nicht sicher, warum eine zweite Abfrage ausgeführt wird, aber das erwartete Verhalten von NHiNRNATE ist, wenn Sie nach derselben Sitzung nach demselben Objekt fragen, erhalten Sie den ersten Level -Cache.

Nach meinem Verständnis sagen Sie bei Verwendung eines Kriteriums im Grunde genommen zu NhiberNate: "Ich möchte Zeilen basierend auf Ausdrücken filtern". Wenn Nhibernate so gesehen wird, kann er nicht wissen, ob die Abfrage immer dieselbe gefilterte Zeile aus der Datenbank zurückgibt, sodass sie erneut abfragen muss.

Außerdem können Sie nach Abfragen nur mit dem Abschnitt der zweiten Stufe nach der Dokumentation einreichen:

Daher sollte der Abfrage-Cache immer in Verbindung mit dem Cache der zweiten Ebene verwendet werden.

Aus hier

Nhibernate gibt wahrscheinlich ein Update zwischen den ersten und den zweiten Abfragen, um Sie vor einem Parallelitätsproblem zu schützen. Wie Frederik betonte, sollten Sie immer verwenden Get ein Objekt nach seinem Schlüssel abzurufen.

Ich bin neugierig, was ist das PrimaryKeyId Wrapper Hinzufügen?

BEARBEITEN:

Allerdings funktioniert es (mein Geld ist noch vor der Auswahl), dieses Verhalten ist entworfen. Wenn Sie Ihr In-Memory-Objekt verwerfen und eine neue Instanz davon aus der Sitzung laden möchten, dann dann aus der Sitzung Evict Das Original aus der Sitzung zuerst. Da ist auch ein Refresh Methode, die Sie versuchen könnten.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top