Dies mag eine triviale Frage sein, aber: Da das ADO.NET-Entitätsframework Änderungen (in generierten Entitäten) automatisch verfolgt und daher die ursprünglichen Werte beibehält, wie kann ich Änderungen an den Entitätsobjekten rückgängig machen?
Ich habe ein Formular, mit dem der Benutzer eine Reihe von "Kunden" -Entitäten in einer Rasteransicht bearbeiten kann.
Jetzt habe ich zwei Schaltflächen "Akzeptieren" und "Zurücksetzen": Wenn auf "Akzeptieren" geklickt wird, rufe ich auf Context.SaveChanges()
und die geänderten Objekte werden in die Datenbank zurückgeschrieben. Wenn auf "Zurücksetzen" geklickt wird, möchte ich, dass alle Objekte ihre ursprünglichen Eigenschaftswerte erhalten. Was wäre der Code dafür?
Vielen Dank
quelle
Context.Refresh()
ein Gegenbeispiel zu Ihrer Behauptung, dass es keine Rücksetzoperation gibt? Die VerwendungRefresh()
scheint ein besserer Ansatz zu sein (dh leichter auf bestimmte Entitäten abzuzielen), als den Kontext zu entsorgen und alle nachverfolgten Änderungen zu verlieren.Fragen Sie den ChangeTracker von DbContext nach schmutzigen Elementen ab. Setzen Sie den Status gelöschter Elemente auf unverändert und hinzugefügte Elemente auf getrennt. Verwenden Sie für geänderte Elemente Originalwerte und legen Sie die aktuellen Werte des Eintrags fest. Setzen Sie den Status des geänderten Eintrags schließlich auf unverändert:
quelle
State
auf EntityState.Unchanged überschreibt auch alle Werte mit,Original Values
sodass keineSetValues
Methode aufgerufen werden muss.Nach MSDN :
Beachten Sie, dass das Zurücksetzen der Anforderung zur Datenbank einige Nachteile hat:
quelle
Das hat bei mir funktioniert:
Wo
item
soll die Kundeneinheit zurückgesetzt werden?quelle
Einfacher Weg ohne Änderungen nachzuverfolgen. Es sollte schneller sein, als alle Entitäten zu betrachten.
quelle
Rollback
, was es zu einer weitaus besseren Wahl macht, wenn man den gesamten Datenbankstatus zurücksetzen möchte. Rollback könnte Kirsche pflücken.50ms+0*n= 50ms
. O (n) bedeutet, dass die Leistung von der Anzahl der Objekte beeinflusst wird ... die Leistung ist möglicherweise2ms+0.5ms*n
... also unter 96 Objekten wäre es schneller, aber die Zeit würde linear mit der Datenmenge zunehmen.Es hat bei mir funktioniert. Sie müssen jedoch Ihre Daten aus dem Kontext neu laden, um die alten Daten zu erhalten. Quelle hier
quelle
"Das hat bei mir funktioniert:
Wo
item
soll die Kundeneinheit zurückgesetzt werden? "Ich habe Tests mit ObjectContext.Refresh in SQL Azure durchgeführt, und "RefreshMode.StoreWins" löst für jede Entität eine Abfrage für die Datenbank aus und verursacht einen Leistungsverlust. Basierend auf der Microsoft-Dokumentation ():
ClientWins: Eigenschaftsänderungen an Objekten im Objektkontext werden nicht durch Werte aus der Datenquelle ersetzt. Beim nächsten Aufruf von SaveChanges werden diese Änderungen an die Datenquelle gesendet.
StoreWins: Eigenschaftsänderungen, die an Objekten im Objektkontext vorgenommen wurden, werden durch Werte aus der Datenquelle ersetzt.
ClientWins ist auch keine gute Idee, da durch das Auslösen von .SaveChanges "verworfene" Änderungen an der Datenquelle vorgenommen werden.
Ich weiß noch nicht, was der beste Weg ist, da das Entsorgen des Kontexts und das Erstellen eines neuen Kontexts eine Ausnahme mit der Meldung "Der zugrunde liegende Anbieter ist beim Öffnen fehlgeschlagen" verursacht, wenn ich versuche, eine Abfrage für einen neu erstellten Kontext auszuführen.
Grüße,
Henrique Clausing
quelle
Für mich ist es besser, für
EntityState.Unchanged
jede Entität festzulegen, für die Sie Änderungen rückgängig machen möchten. Dies stellt sicher, dass Änderungen in FK rückgängig gemacht werden und eine etwas klarere Syntax haben.quelle
Ich fand, dass dies in meinem Kontext gut funktioniert:
Context.ObjectStateManager.ChangeObjectState(customer, EntityState.Unchanged);
quelle
DbContext.SaveChanges()
, aber es werden die Entitätswerte nicht auf die ursprünglichen Werte zurückgesetzt. Und wenn der Entitätsstatus aufgrund einer späteren Änderung geändert wird, bleiben möglicherweise alle vorherigen Änderungen beim Speichern erhalten?Dies ist ein Beispiel dafür, wovon Mrnka spricht. Die folgende Methode überschreibt aktuelle Werte des Unternehmens mit den ursprünglichen Werten und nicht rufen Sie die Datenbank aus. Dazu verwenden wir die OriginalValues-Eigenschaft von DbEntityEntry und verwenden die Reflexion, um Werte generisch festzulegen. (Dies funktioniert ab EntityFramework 5.0)
quelle
Wir verwenden EF 4 mit dem Legacy-Objektkontext. Keine der oben genannten Lösungen hat dies direkt für mich beantwortet - obwohl es auf lange Sicht beantwortet wurde, indem es mich in die richtige Richtung drängte.
Wir können den Kontext nicht einfach entsorgen und neu erstellen, da einige der Objekte, die wir im Speicher haben (verdammt noch mal das faule Laden !!), immer noch mit dem Kontext verbunden sind, aber untergeordnete Elemente haben, die noch geladen werden müssen. In diesen Fällen müssen wir alles auf die ursprünglichen Werte zurücksetzen, ohne die Datenbank zu hämmern und ohne die bestehende Verbindung zu trennen.
Nachfolgend finden Sie unsere Lösung für dasselbe Problem:
Ich hoffe das hilft anderen.
quelle
Einige gute Ideen oben, ich habe mich entschieden, ICloneable und dann eine einfache Erweiterungsmethode zu implementieren.
Hier gefunden: Wie klone ich eine generische Liste in C #?
Zu verwenden als:
Auf diese Weise konnte ich meine Produktentitätsliste klonen, auf jeden Artikel einen Rabatt gewähren und musste mich nicht darum kümmern, Änderungen an der ursprünglichen Entität zurückzusetzen. Sie müssen nicht mit dem DBContext sprechen und nach einer Aktualisierung fragen oder mit dem ChangeTracker arbeiten. Man könnte sagen, ich nutze EF6 nicht vollständig, aber dies ist eine sehr schöne und einfache Implementierung, die einen DB-Treffer vermeidet. Ich kann nicht sagen, ob dies einen Leistungseinbruch hat oder nicht.
quelle