NHibernate Session.Flush() sendet Aktualisierungsabfragen, wenn keine Aktualisierung erfolgt ist

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

  •  09-06-2019
  •  | 
  •  

Frage

Ich habe eine NHibernate-Sitzung.In dieser Sitzung führe ich genau eine Operation aus, nämlich diesen Code auszuführen, um eine Liste zu erhalten:

public IList<Customer> GetCustomerByFirstName(string customerFirstName)
{
return _session.CreateCriteria(typeof(Customer))
    .Add(new NHibernate.Expression.EqExpression("FirstName", customerFirstName))
    .List<Customer>();
}

ich rufe an Session.Flush() am Ende von HttpRequest, und ich bekomme ein HibernateAdoException.NHibernate übergibt eine Update-Anweisung an die Datenbank und verursacht eine Fremdschlüsselverletzung.Wenn ich das nicht ausführe flush, wird die Anfrage ohne Probleme abgeschlossen.Das Problem hierbei ist, dass ich den Flush an Ort und Stelle benötige, falls es zu einer Änderung in anderen Sitzungen kommt, da dieser Code in anderen Bereichen wiederverwendet wird.Gibt es eine andere Konfigurationseinstellung, die mir möglicherweise fehlt?


Hier ist der Code aus der Ausnahme:

[SQL: UPDATE CUSTOMER SET first_name = ?, last_name = ?, strategy_code_1 = ?, strategy_code_2 = ?, strategy_code_3 = ?, dts_import = ?, account_cycle_code = ?, bucket = ?, collector_code = ?, days_delinquent_count = ?, external_status_code = ?, principal_balance_amount = ?, total_min_pay_due = ?, current_balance = ?, amount_delinquent = ?, current_min_pay_due = ?, bucket_1 = ?, bucket_2 = ?, bucket_3 = ?, bucket_4 = ?, bucket_5 = ?, bucket_6 = ?, bucket_7 = ? WHERE customer_account_id = ?]

Es werden keine Parameter als übergeben angezeigt.

War es hilfreich?

Lösung

Ich habe dies schon einmal gesehen, als eines meiner Modelle nicht korrekt zugeordnet wurde (nullfähige Typen nicht korrekt verwendet wurden).Könnten Sie bitte Ihr Modell und Ihre Zuordnung einfügen?

Andere Tipps

Seien Sie immer vorsichtig mit NULL-fähigen Feldern, wenn Sie mit NHibernate arbeiten.Wenn Ihr Feld in der Datenbank NULL-fähig ist, stellen Sie sicher, dass die entsprechende .NET-Klasse ebenfalls den Typ Nullable verwendet.Ansonsten passieren alle möglichen seltsamen Dinge.Das Symptom besteht normalerweise darin, dass NHibernate versucht, den Datensatz in der Datenbank zu aktualisieren, obwohl Sie keine Felder geändert haben, seit Sie die Entität aus der Datenbank gelesen haben.

Die folgende Sequenz erklärt, warum dies geschieht:

  1. NHibernate ruft mithilfe von ADO.NET die Rohdaten der Entität aus der Datenbank ab
  2. NHibernate erstellt die Entität und legt ihre Eigenschaften fest
  3. Wenn das DB-Feld NULL enthält, wird die Eigenschaft auf den Standardwert für ihren Typ gesetzt:
    • Eigenschaften von Referenztypen werden auf null gesetzt
    • Eigenschaften von Ganzzahl- und Gleitkommatypen werden auf 0 gesetzt
    • Eigenschaften vom booleschen Typ werden auf „false“ gesetzt
    • Eigenschaften vom Typ DateTime werden auf DateTime.MinValue festgelegt
    • usw.
  4. Wenn nun die Transaktion festgeschrieben wird, vergleicht NHibernate den Wert der Eigenschaft mit dem ursprünglichen Feldwert, den es aus der Datenbank gelesen hat, und da das Feld NULL enthielt, die Eigenschaft jedoch einen Wert ungleich Null, NHibernate betrachtet die Eigenschaft als fehlerhaft und erzwingt eine Aktualisierung der Entität.

Dies beeinträchtigt nicht nur die Leistung (Sie erhalten bei jedem Abrufen der Entität einen zusätzlichen Roundtrip zur Datenbank und eine zusätzliche Aktualisierung), sondern kann auch dazu führen, dass Fehler bei DateTime-Spalten schwer zu beheben sind.Wenn die DateTime-Eigenschaft auf ihren Standardwert initialisiert wird, wird sie tatsächlich auf den 1.1.0001 gesetzt.Wenn dieser Wert in der Datenbank gespeichert wird, kann der SqlClient von ADO.NET ihn nicht in einen gültigen SqlDateTime-Wert konvertieren, da der kleinstmögliche SqlDateTime der 1.1.1753 ist!!!

Die einfachste Lösung besteht darin, dafür zu sorgen, dass die Klasseneigenschaft den Nullable-Typ verwendet, in diesem Fall „DateTime?“.Alternativ können Sie einen benutzerdefinierten Typ-Mapper implementieren, indem Sie IUserType mit seiner Equals-Methode implementieren und DbNull.Value ordnungsgemäß mit dem Standardwert Ihres Werttyps vergleichen.In unserem Fall müsste Equals beim Vergleich von 1/1/0001 mit DbNull.Value „true“ zurückgeben.Die Implementierung eines voll funktionsfähigen IUserType ist nicht wirklich schwierig, erfordert jedoch Kenntnisse über NHibernate-Trivia. Bereiten Sie sich also darauf vor, gründlich zu googeln, wenn Sie sich für diesen Weg entscheiden.

Dieses Problem trat auch in NH 2.0.1 auf, als ich versuchte, die umgekehrten Enden von Many-to-Many-Beuteln mit access="noop" zu verbergen (Hinweis:das funktioniert nicht).

Durch die Konvertierung in „access="field" + das Hinzufügen eines Felds zur Klasse wurde das Problem behoben.Allerdings ist es ziemlich schwierig, sie aufzuspüren.

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