Wenn ich mich in einem getrennten Szenario befinde und vom Client ein Dto erhalte, das ich einer Entität zuordne, um es zu speichern, gehe ich folgendermaßen vor:
context.Entry(entity).State = EntityState.Modified;
context.SaveChanges();
Für was ist dann die DbSet.Attach(entity)
oder warum sollte ich die .Attach-Methode verwenden, wenn EntityState.Modified die Entität bereits anfügt?
c#
entity-framework
entity-framework-6
Elisabeth
quelle
quelle
Antworten:
Wenn Sie dies tun
context.Entry(entity).State = EntityState.Modified;
, hängen Sie die Entität nicht nur an die anDbContext
, sondern markieren auch die gesamte Entität als fehlerhaft. Dies bedeutet, dasscontext.SaveChanges()
EF in diesem Fall eine Aktualisierungsanweisung generiert, die alle Felder der Entität aktualisiert .Dies ist nicht immer erwünscht.
Hängt andererseits
DbSet.Attach(entity)
die Entität an den Kontext an, ohne sie als schmutzig zu markieren. Es ist gleichbedeutend mit Tuncontext.Entry(entity).State = EntityState.Unchanged;
Wenn Sie beim Anhängen auf diese Weise eine Eigenschaft für die Entität
context.SaveChanges()
aktualisieren, generiert EF beim nächsten Aufruf keine Datenbankaktualisierung für diese Entität.Selbst wenn Sie vorhaben, eine Entität zu aktualisieren, wenn die Entität viele Eigenschaften (DB-Spalten) hat, Sie aber nur einige aktualisieren möchten, ist es möglicherweise vorteilhaft, eine
DbSet.Attach(entity)
durchzuführen und dann nur die wenigen Eigenschaften zu aktualisieren das muss aktualisiert werden. Auf diese Weise wird eine effizientere Update-Anweisung von EF generiert. EF aktualisiert nur die von Ihnen geänderten Eigenschaften (im Gegensatz dazucontext.Entry(entity).State = EntityState.Modified;
werden alle Eigenschaften / Spalten aktualisiert).Relevante Dokumentation: Add / Attach und Entity States .
Codebeispiel
Angenommen, Sie haben die folgende Entität:
Wenn Ihr Code so aussieht:
Das generierte SQL sieht ungefähr so aus:
Beachten Sie, wie die obige Update-Anweisung alle Spalten aktualisiert, unabhängig davon, ob Sie die Werte tatsächlich geändert haben oder nicht.
Im Gegensatz dazu, wenn Ihr Code den "normalen" Anhang wie folgt verwendet:
Dann ist die generierte Update-Anweisung anders:
Wie Sie sehen können, aktualisiert die Update-Anweisung nur die Werte, die tatsächlich geändert wurden, nachdem Sie die Entität an den Kontext angehängt haben. Abhängig von der Struktur Ihrer Tabelle kann sich dies positiv auf die Leistung auswirken.
Welche Option für Sie besser ist, hängt ganz davon ab, was Sie versuchen.
quelle
WHERE
Klausel nur den Primärschlüssel enthält und keine Parallelitätsprüfung durchgeführt wird. Um die Parallelität zu überprüfen, muss ich eine Spalte explizit als Parallelitätstoken oder rowVersion konfigurieren. In diesem Fall enthält dieWHERE
Klausel nur den Primärschlüssel und die Spalte für das Parallelitätstoken, nicht alle Felder. Wenn Ihre Tests etwas anderes zeigen, würde ich gerne davon hören.DbContext.Entry(person).CurrentValues
undDbContext.Entry(person).OriginalValues
.Wenn Sie die
DbSet.Update
Methode verwenden, markiert Entity Framework alle Eigenschaften Ihrer Entität alsEntityState.Modified
und verfolgt sie so. Wenn Sie nur einige Ihrer Eigenschaften ändern möchten, nicht alleDbSet.Attach
. Diese Methode erstellt alle Ihre EigenschaftenEntityState.Unchanged
, daher müssen Sie Ihre Eigenschaften erstellen, die Sie aktualisieren möchtenEntityState.Modified
. Wenn die App auf trifftDbContext.SaveChanges
, werden nur geänderte Eigenschaften ausgeführt.quelle
Nur zusätzlich (zu der markierten Antwort) gibt es einen wichtigen Unterschied zwischen
context.Entry(entity).State = EntityState.Unchanged
undcontext.Attach(entity)
(in EF Core):Ich habe einige Tests durchgeführt, um es selbst besser zu verstehen (daher umfasst dies auch einige allgemeine Referenztests). Dies ist also mein Testszenario:
QueryTrackingBehavior.NoTracking
Dies sind die Modelle:
Dies sind die (ursprünglichen) Testdaten in der Datenbank:
So erhalten Sie die Bestellung:
Nun die Tests:
Einfaches Update mit EntityState :
Einfaches Update mit Anhängen :
Update mit Änderung der untergeordneten IDs mit EntityState :
Update mit Änderung der untergeordneten IDs mit Anhängen :
Hinweis: Dies löst eine Ausnahme aus, unabhängig davon, ob die ID geändert oder auf den ursprünglichen Wert gesetzt wurde. Der Status der ID scheint auf "geändert" gesetzt zu sein, und dies ist nicht zulässig (da es sich um den Primärschlüssel handelt).
Update mit Änderung der untergeordneten IDs als neu (kein Unterschied zwischen EntityState und Attach):
Hinweis: Sehen Sie den Unterschied zum Update mit EntityState ohne neues (oben). Dieses Mal wird der Name aufgrund der neuen Benutzerinstanz aktualisiert.
Update mit Änderung der Referenz- IDs mit EntityState :
Update mit Änderung der Referenz-IDs mit Anhängen :
Hinweis: Die Referenz wird in Benutzer 3 geändert, aber auch Benutzer 1 wird aktualisiert. Ich denke, dies liegt daran, dass der
order.OrderedByUser.Id
unverändert ist (es ist immer noch 1).Fazit Mit EntityState haben Sie mehr Kontrolle, müssen jedoch die Untereigenschaften (zweite Ebene) selbst aktualisieren. Mit Anhängen können Sie alles aktualisieren (ich denke mit allen Eigenschaftenebenen), aber Sie müssen die Referenzen im Auge behalten. Nur zum Beispiel: Wenn User (OrderedByUser) ein DropDown wäre, könnte das Ändern des Werts über ein DropDown das gesamte User-Objekt überschreiben. In diesem Fall würde der ursprüngliche dropDown-Wert anstelle der Referenz überschrieben.
Für mich ist der beste Fall, Objekte wie OrderedByUser auf null zu setzen und nur die order.OrderedByUserId auf den neuen Wert zu setzen, wenn ich nur die Referenz ändern möchte (egal ob EntityState oder Attach).
Hoffe das hilft, ich weiß es ist viel Text: D.
quelle