2010-11-19 11 views
1

Ich arbeite an einem NHibernate-Projekt und habe eine Frage bezüglich der Aktualisierung von transienten Entitäten.NHibernate - bestimmte Eigenschaften als 'dirty' kennzeichnen

Grundsätzlich ist der Arbeitsablauf ist wie folgt:

  1. einen DTO Erstellen (Vorsprung) und den Draht an den Client senden über. Dies hat eine kleine Teilmenge von Eigenschaften von der Entität.
  2. Client sendet den geänderten DTO zurück
  3. Ordnen Sie die DTO-Eigenschaften wieder der entsprechenden Entität zu, damit eine UPDATE-Anweisung generiert und von NH ausgeführt werden kann.
  4. speichern das Unternehmen

Punkt 4 ist, wo ich das Problem. Derzeit kann ich dieses Update mit der Methode session.Merge() erreichen, allerdings muss es zuerst die Entity vor dem Update von der db laden (keine 2LC annehmen). Daher werden sowohl eine Auswahl- als auch eine Aktualisierungsanweisung ausgelöst.

Was ich tun möchte, ist eine transiente Instanz der Entität zu erstellen, die neuen Werte aus dem DTO abzubilden, dann NH generieren eine SQL-Anweisung nur mit den Eigenschaften, die ich geändert habe. Die zusätzliche Auswahl sollte nicht notwendig sein, da ich bereits die Entitäts-ID und die für die SET-Klausel erforderlichen Werte habe. Ist das in NH möglich?

Momentan mit session.Update() werden alle Eigenschaften in die update-Anweisung aufgenommen und eine Ausnahme wird aufgrund der nicht initialisierten Eigenschaften ausgelöst, die nicht Teil des DTO sind.

Im Wesentlichen brauche ich einen Weg, um anzugeben, welche Entity-Eigenschaften schmutzig sind, so dass nur diese im Update enthalten sind.

== == EDIT

Zum Beispiel ...

public class Person 
{ 
    public virtual int PersonId { get; set; } 
    public virtual string Firstname { get; set; } 
    public virtual string Nickname { get; set; }  
    public virtual string Surname { get; set; } 
    public virtual DateTime BirthDate { get; set; }  
} 

Und der Testfall.

// Create the transient entity 
Person p = new Person() 
p.id = 1; 

using (ISession session = factory.OpenSession()) 
{ 
    session.Update(p); 

    // Update the entity – now attached to session  
    p.Firstname = “Bob”; 

    session.Flush(); 
} 

Ich hatte gehofft, eine SQL-Anweisung ähnlich zu ‚UPDATE Personen SET Vorname =‚Bob‘WHERE PersonID = 1‘ zu erzeugen. Stattdessen erhalte ich eine DateTime out of range-Ausnahme, da BirthDate nicht initialisiert wird. Es sollte nicht BirthDate benötigen, da es für die SQL-Anweisung nicht benötigt wird. Vielleicht ist das nicht möglich?

==/EDIT ==

Vielen Dank im Voraus, John

Antwort

4

Dynamic Update ist das, was Sie suchen. In Ihrer Zuordnungsdatei (hbm.xml):

Beachten Sie die möglichen Probleme, die dies verursachen kann. Nehmen wir an, Sie haben eine Domänenlogik, die besagt, dass entweder Vorname oder Pseudonym nicht null sein darf. (Komplettiert das Ganze.) Zwei Leute aktualisieren Jon "Jonboy" Jonson zur gleichen Zeit. Einer entfernt seinen Vornamen. Da dynamic-update wahr ist, löscht die update-Anweisung nur Jon und der Datensatz lautet jetzt "Jonboy" Jonson. Das andere gleichzeitige Update entfernt seinen Spitznamen. Die Absicht ist Jon Jonboy. Aber nur der Nullpunkt des Spitznamens wird an die Datenbank gesendet. Sie haben jetzt einen Datensatz ohne Vorname oder Spitzname.Wenn dynamic-update falsch gewesen wäre, hätte das zweite Update es auf Jon Jonboy gesetzt. Vielleicht ist das in Ihrer Situation kein Problem, aber die Einstellung dynamic-update = "true" hat Konsequenzen und Sie sollten die Implikationen durchdenken.

UPDATE: Danke für den Code. Das hat geholfen. Das Hauptproblem ist, dass NHibernate nicht genügend Informationen hat. Wenn Sie session.Update (p) sagen, muss NHibernate der aktuellen Sitzung eine getrennte Entität zuordnen. Es hat eine nicht standardmäßige PK. Daher weiß NHibernate, dass es sich um ein Update handelt und nicht um eine Einfügung. Wenn Sie session.Update (p) sagen, sieht NHibernate das gesamte Objekt als fehlerhaft und sendet es an die Datenbank. (Wenn Sie session.Merge (obj) verwenden, wählt NHibernate die Entität aus der Datenbank aus und führt obj damit zusammen.) Das ist nicht das, was Sie wirklich meinen. Sie möchten Ihr Objekt der aktuellen Sitzung zuordnen, aber als sauber markieren. Die API ist etwas nicht intuitiv. Sie verwenden session.Lock (obj, LockMode.None) wie folgt.

using(var session = sessionFactory.OpenSession()) 
using(var tx = session.BeginTransaction()) { 
    var p = new Person {PersonId = 1}; 
    session.Lock(p, LockMode.None); // <-- This is the secret sauce! 
    p.Firstname = "Bob"; 
    // No need to call session.Update(p) since p is already associated with the session. 
    tx.Commit(); 
} 

(NB dynamisch-update = "true" wird in meinem Mapping angegeben.)

Dies ist in der folgenden SQL-Ergebnisse:

UPDATE Person 
SET Firstname = 'Bob' /* @p0_0 */ 
WHERE PersonId = 1 /* @p1_0 */ 
+0

Es gibt auch Auswirkungen auf die Leistung dieser auch mit Ich glaube, dass die Verwendung von statischen Updates (insgesamt) leistungsfähiger ist, da nhibernate die update-Anweisungen vorbereitet, wenn die sessionfactory erstellt wird. – DanP

+0

Hallo James, Danke für die Antwort. Ich habe das DynamicUpdate (fließendes Mapping) für die Entität festgelegt. Vielleicht wird ein Beispiel das Problem verdeutlichen. Bitte beachten Sie den obigen Abschnitt. – John

+0

Ich muss zustimmen, dass die API in diesem Fall nicht intuitiv ist;) Ich habe mit Session.Lock() in meiner "Real-World" -App getestet und es gibt genau das SQL zurück, das ich möchte. Vielen Dank für Ihre Hilfe mit diesem James. – John