2017-03-03 1 views
1

Ich repariere gerade eine alte Windows-Anwendungen und begegnete NHibernate Fehler. Ich habe gelesen und probiert einige Dinge im Netz, aber am Ende Fehler.NHibernate SaveOrUpdate Fehler

Hier ist mein Code für die ISession:

Public ReadOnly Property session() As ISession 
    Get 
     If IsNothing(m_session) Then 
      m_session = Factory.InitConfiguration.OpenSession() 
     End If 
     Return m_session 
    End Get 
End Property 

Hier ist mein Code für die Schaltfläche Speichern ist:

 Try 
      session.BeginTransaction() 
      SetParent(x_object) 
      'session.clear() 
      session.Flush() 
      session.SaveOrUpdate(x_object) 
      session.Transaction.Commit() 
      compObj.IsNew = False 
      Return True 
    Catch ex As Exception 
     AppServices.ErrorMessage = ex.Message 
     session.Transaction.Rollback() 
     Return False 
    Finally 
     'TBA 
    End Try 

das Problem Also hier beginnen, ich habe dieses Datum Spalte als Datum- und AttachmentList .

Der aktuelle Code hat kein Problem, bis der Benutzer im Jahr weniger als 1753. Aber der Code fängt den Fehler richtig und zeigt die Nachricht und wenn der Benutzer weiterhin den Jahr-Tippfehler beheben, wird es fange immer noch den Fehler (während ich bei der Uhr bin, bekomme ich schon den neuen Wert), bis der Benutzer die Anwendung schließt und sie wieder öffnet.

Allerdings, wenn ich die session.clear() auskommentieren, wird es gut tun, kann der Benutzer ihre Tippfehler beheben und weiterhin Datensatz zu speichern, aber wenn der Benutzer die andere Aktion sagen Anlage sagen, wird es eine andere bekommen Error. Die Befestigung Aktion wie folgt:

  1. Anlage hinzufügen
  2. Klicken Sie auf Speichern
  3. hinzufügen Befestigung
  4. Schaltfläche Speichern
  5. New Fehler klicken.

enter image description here

So beraten Sie mich auf, was getan werden muss. Ich habe versucht, zu fusionieren, ich habe versucht, zu aktualisieren, zu speichern, zu vertreiben, aber am Ende Fehler. Ich denke mein Problem ist, wie ich die Sitzung arrangiere, ist die Hauptquelle des Problems.

+0

Was ist der Umfang von 'm_session' und' x_object'? Ordnen Sie Ihre Entitäten etwas anderem als DTO zu? –

+0

@A_J Ja, ich ordne die Entitäten auf viele untergeordnete Elemente zu und setze sie als 1 Elternelement. Allerdings ist mein Problem durch Frederic Erklärung gelöst. Sie können sich darauf beziehen, warum. –

Antwort

0

Es sieht so aus, als ob der Code, den Sie verarbeiten müssen, versucht, eine Sitzung fortzusetzen, die einen fehlgeschlagenen Flush- oder Transaktions-Commit durchlaufen hat.

Dies ist ein Anti-Pattern. Von NHibernate reference:

:

Die Verwendung von NHibernate kann zu Ausnahmen führen, normalerweise HibernateException. Diese Ausnahme kann eine verschachtelte innere Ausnahme (die Grundursache) haben, verwenden Sie die InnerException-Eigenschaft, um darauf zuzugreifen.

Wenn die ISession eine Ausnahme auslöst, sollten Sie sofort die Transaktion zurücksetzen, rufen Sie ISession.Close() auf und verwerfen Sie die ISession Instanz. Bestimmte Methoden von ISession werden die Sitzung nicht in einem konsistenten Zustand verlassen.

...

Die folgende Ausnahmebehandlung Idiom zeigt den typischen Fall in NHibernate Anwendungen:

using (ISession sess = factory.OpenSession()) 
using (ITransaction tx = sess.BeginTransaction()) 
{ 
    // do some work 
    ... 
    tx.Commit(); 
} 

Oder bei der manuellen Verwaltung von ADO.NET Transaktionen:

ISession sess = factory.openSession(); 
try 
{ 
    // do some work 
    ... 
    sess.Flush(); 
    currentTransaction.Commit(); 
} 
catch (Exception e) 
{ 
    currentTransaction.Rollback(); 
    throw; 
} 
finally 
{ 
    sess.Close(); 
} 

Sie muss sicherstellen, dass der Code nicht versucht, die Sitzung nach einer Ausnahme weiter zu verwenden.

Darüber hinaus sieht es so aus, als ob die Sitzung geöffnet bleibt, während sie auf Benutzerinteraktion wartet: Dies ist kein empfohlenes Muster. Eine NHibernate-Sitzung ist normalerweise von kurzer Dauer. Das Öffnen einer Sitzung ist billig.

Ein übliches Muster ist, es zu öffnen, wenn es beginnt, ein Ereignis von Benutzereingaben zu verarbeiten und es zu schließen, bevor die Ereignisverarbeitung beendet wird, um es nicht geöffnet zu lassen, während der Benutzer einen Kaffee nimmt.

Jetzt kann es schwierig werden, die Anwendungssitzungsverwaltung zu ändern, insbesondere wenn die Anwendung Verweise auf Entitäten enthält und erwartet, dass sie weiterhin an eine geöffnete Sitzung gebunden sind, nachdem auf Benutzerinteraktion gewartet wurde.

Wenn die Sitzung zwischen Benutzerinteraktion geöffnet bleibt, um den Cache der ersten Ebene zu aktivieren (Sitzungsentitätscache), sollten Sie stattdessen den Cache der zweiten Ebene aktivieren.

+0

Jetzt verstehe ich endlich von Ihrer Erklärung und hat mein Problem gelöst, Ihre Erklärung hilft mir, eine Lösung zu finden, aber am Ende verwende ich SaveOrUpdateCopy für das Objekt mit Ihrer Code-Logik. Jetzt ist es an der Zeit, diese alte Methode in eine neue zu verwandeln. Danke Bruder für deine Erklärung! –

0

Sie haben den Umfang Ihres Objekts m_session und x_object nicht erwähnt. Außerdem haben Sie nicht erwähnt, wie Sie mit Entitäten umgehen. Ordnen Sie Ihre Entitäten etwas anderem als DTO zu?

Lassen Sie uns sehen, warum dies geschieht:

Dies aufgrund der ersten Ebene (Session) Cache passieren kann. Sie versuchen, SaveOrUpdate eine Entität; Es schlägt aufgrund falscher Daten fehl. Die Entität befindet sich jedoch weiterhin im Sitzungscache. Dann korrigiert der Benutzer den Fehler und speichert erneut. Sie tun SaveOrUpdate wieder mit NEW Einheit, die Konflikt mit Entität bereits in der Sitzung. Identifikator beider Entitäten ist gleich.

Siehe this und this Frage.

Wenn Sie session.clear() auskommentieren, wird die erste Entität von der Sitzung entfernt und Ihre neue Entität funktioniert ordnungsgemäß, da es jetzt keinen Konflikt gibt.

Die Links, die ich oben erwähnte, schlagen auch vor, wie dieses Szenario statt clear() behandelt wird.

Clear ist keine gute Lösung in meinem Verständnis; Es wird die gesamte Sitzung gelöscht. Evict ist eine bessere Alternative.Wenn Evict für Sie nicht funktioniert, können Sie die korrekte Instanz nicht löschen.

Folgendes ist C# -Code; Sie müssen es VB.NET übersetzen: -

try 
{ 
    nhSession.SaveOrUpdate(instance); 
} 
catch(NonUniqueObjectException) 
{ 
    T instanceFromCache = GetInstanceFromCache<T>(instance); 
    nhSession.Evict(instanceFromCache); 
    nhSession.SaveOrUpdate(instance); 
} 

Sie GetInstanceFromCache Verfahren von einem der Links bekommen kann ich oben erwähnt.

+1

Ihre Methode funktioniert für mich, aber es ist ein bisschen langsamer und neuere Problem auf der anderen Registerkarte angetroffen. Jedoch ist mein Problem gelöst, basierend auf der Antwort von @ Frederic Post bei der Verwendung von Saveorupdatecopy. Vielen Dank Kumpel für Ihre Erklärung, ich verstehe jetzt NHibernate, wie ich diese Dinge neu erkunde. –

Verwandte Themen