Kurz gesagt, die Ausnahme wird während des POSTing-Wrapper-Modells ausgelöst und der Status eines Eintrags in "Geändert" geändert. Vor dem Ändern des Status wird der Status auf "Abgelöst" gesetzt, aber das Aufrufen von Attach () löst denselben Fehler aus. Ich benutze EF6.
Unten finden Sie meinen Code (Modellnamen wurden geändert, um das Lesen zu erleichtern).
Modell
// Wrapper classes
public class AViewModel
{
public A a { get; set; }
public List<B> b { get; set; }
public C c { get; set; }
}
Regler
public ActionResult Edit(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
if (!canUserAccessA(id.Value))
return new HttpStatusCodeResult(HttpStatusCode.Forbidden);
var aViewModel = new AViewModel();
aViewModel.A = db.As.Find(id);
if (aViewModel.Receipt == null)
{
return HttpNotFound();
}
aViewModel.b = db.Bs.Where(x => x.aID == id.Value).ToList();
aViewModel.Vendor = db.Cs.Where(x => x.cID == aViewModel.a.cID).FirstOrDefault();
return View(aViewModel);
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(AViewModel aViewModel)
{
if (!canUserAccessA(aViewModel.a.aID) || aViewModel.a.UserID != WebSecurity.GetUserId(User.Identity.Name))
return new HttpStatusCodeResult(HttpStatusCode.Forbidden);
if (ModelState.IsValid)
{
db.Entry(aViewModel.a).State = EntityState.Modified; //THIS IS WHERE THE ERROR IS BEING THROWN
db.SaveChanges();
return RedirectToAction("Index");
}
return View(aViewModel);
}
Wie oben gezeigt
db.Entry(aViewModel.a).State = EntityState.Modified;
löst eine Ausnahme aus:
Das Anhängen einer Entität vom Typ 'A' ist fehlgeschlagen, da eine andere Entität desselben Typs bereits denselben Primärschlüsselwert hat. Dies kann passieren, wenn Sie die Methode "Anhängen" verwenden oder den Status einer Entität auf "Unverändert" oder "Geändert" setzen, wenn Entitäten im Diagramm widersprüchliche Schlüsselwerte aufweisen. Dies kann daran liegen, dass einige Entitäten neu sind und noch keine von der Datenbank generierten Schlüsselwerte erhalten haben. Verwenden Sie in diesem Fall die Methode 'Hinzufügen' oder den Entitätsstatus 'Hinzugefügt', um das Diagramm zu verfolgen, und setzen Sie den Status nicht neuer Entitäten entsprechend auf 'Unverändert' oder 'Geändert'.
Hat jemand etwas Falsches in meinem Code gesehen oder verstanden, unter welchen Umständen ein solcher Fehler beim Bearbeiten eines Modells auftreten würde?
quelle
EntityState
? Da Ihre Entität aus einer Post-Anfrage stammt, sollte sie nicht vom aktuellen Kontext erfasst werden. Ich denke, dass Sie versuchen, einen Artikel mit einer vorhandenen IDdb
Instanz zwischen Ihren beiden Aktionen identisch ist, kann dies Ihr Problem erklären, da Ihr Element von der GET-Methode geladen wird (dann vom Kontext verfolgt wird) und die in Ihrer POST-Methode möglicherweise nicht als die zuvor abgerufene Entität erkennt .canUserAccessA()
laden Sie die Einheit direkt oder als eine Beziehung von einem anderen Rechtsträger?Antworten:
Problem gelöst!
Attach
Die Methode könnte möglicherweise jemandem helfen, würde aber in dieser Situation nicht helfen, da das Dokument bereits beim Laden in der Funktion GET-Controller bearbeiten verfolgt wurde. Anhängen würde genau den gleichen Fehler auslösen.Das Problem, auf das ich hier stoße, wurde durch eine Funktion verursacht,
canUserAccessA()
die die A-Entität lädt, bevor der Status von Objekt a aktualisiert wird. Dies hat die verfolgte Entität vermasselt und den Status eines Objekts in geändertDetached
.Die Lösung bestand darin, Änderungen vorzunehmen,
canUserAccessA()
damit das von mir geladene Objekt nicht verfolgt wird. Die FunktionAsNoTracking()
sollte aufgerufen werden, während der Kontext abgefragt wird.Aus irgendeinem Grund konnte ich nicht
.Find(aID)
mit verwenden,AsNoTracking()
aber es spielt keine Rolle, da ich das gleiche erreichen könnte, indem ich die Abfrage ändere .Hoffe das hilft jedem mit ähnlichen Problemen!
quelle
using System.Data.Entity;
verwendenAsNoTracking()
.Interessant:
Oder wenn Sie immer noch nicht generisch sind:
scheint mein Problem reibungslos gelöst zu haben.
quelle
AddOrUpdate
ist eine Erweiterungsmethode imSystem.Data.Entity.Migrations
Namespace.Es scheint, dass die Entität, die Sie ändern möchten, nicht korrekt verfolgt wird und daher nicht als bearbeitet erkannt, sondern stattdessen hinzugefügt wird.
Versuchen Sie Folgendes, anstatt den Status direkt festzulegen:
Außerdem möchte ich Sie warnen, dass Ihr Code eine potenzielle Sicherheitslücke enthält. Wenn Sie die Entität direkt in Ihrem Ansichtsmodell verwenden, besteht das Risiko, dass jemand den Inhalt der Entität ändert, indem er korrekt übermittelte Felder in der übermittelten Form hinzufügt. Wenn der Benutzer beispielsweise ein Eingabefeld mit dem Namen "A.FirstName" hinzufügt und die Entität ein solches Feld enthält, wird der Wert an das Ansichtsmodell gebunden und in der Datenbank gespeichert, selbst wenn der Benutzer dies im normalen Betrieb der Anwendung nicht ändern darf .
Aktualisieren:
Um die zuvor erwähnte Sicherheitslücke zu überwinden, sollten Sie Ihr Domänenmodell niemals als Ansichtsmodell verfügbar machen, sondern stattdessen ein separates Ansichtsmodell verwenden. Dann würde Ihre Aktion ein Ansichtsmodell erhalten, das Sie mit einem Zuordnungstool wie AutoMapper wieder dem Domänenmodell zuordnen können. Dies würde Sie davor schützen, dass Benutzer vertrauliche Daten ändern.
Hier ist eine ausführliche Erklärung:
http://www.stevefenton.co.uk/Content/Blog/Date/201303/Blog/Why-You-Never-Expose-Your-Domain-Model-As-Your-MVC-Model/
quelle
Versuche dies:
quelle
Für mich war die lokale Kopie die Ursache des Problems. das löste es
quelle
Mein Fall war, dass ich von meiner MVC-App aus keinen direkten Zugriff auf den EF-Kontext hatte.
Wenn Sie also eine Art Repository für die Entitätspersistenz verwenden, kann es angebracht sein, die explizit geladene Entität einfach zu trennen und dann den gebundenen EntityState auf Modified zu setzen.
Beispielcode (Zusammenfassung):
MVC
Repository
quelle
Ich dachte, ich würde meine Erfahrungen in diesem Fall teilen, obwohl ich mich ein bisschen albern fühle, weil ich es nicht früher bemerkt habe.
Ich verwende das Repository-Muster mit den Repo-Instanzen, die in meine Controller injiziert werden. Die konkreten Repositorys instanziieren meinen ModelContext (DbContext), der die Lebensdauer des Repositorys dauert, das
IDisposable
vom Controller bereitgestellt wird.Das Problem für mich war, dass ich eine modifizierte Stempel- und Zeilenversion für meine Entitäten habe, sodass ich sie zuerst erhielt, um sie mit den eingehenden Headern zu vergleichen. Dadurch wurde natürlich die Entität geladen und verfolgt, die anschließend aktualisiert wurde.
Die Lösung bestand einfach darin, das Repository von der Neuerstellung eines Kontexts im Konstruktor auf die folgenden Methoden zu ändern:
Auf diese Weise können die Repository-Methoden ihre Kontextinstanz bei jeder Verwendung durch Aufrufen neu erstellen
GetDbContext
oder eine vorherige Instanz verwenden, wenn sie dies wünschen, indem sie true angeben.quelle
Ich habe diese Antwort nur hinzugefügt, weil das Problem anhand eines komplexeren Datenmusters erklärt wird und ich es hier schwer zu verstehen fand.
Ich habe eine ziemlich einfache Anwendung erstellt. Dieser Fehler trat in der Aktion POST bearbeiten auf. Die Aktion akzeptierte ViewModel als Eingabeparameter. Der Grund für die Verwendung des ViewModel bestand darin, einige Berechnungen durchzuführen, bevor der Datensatz gespeichert wurde.
Nachdem die Aktion die Validierung durchlaufen hatte
if(ModelState.IsValid)
, bestand mein Fehlverhalten darin, Werte aus ViewModel in eine völlig neue Instanz von Entity zu projizieren. Ich dachte, ich müsste eine neue Instanz erstellen, um aktualisierte Daten zu speichern, und dann eine solche Instanz speichern.Was ich später festgestellt hatte, war, dass ich den Datensatz aus der Datenbank lesen musste:
und dieses Objekt aktualisiert. Alles funktioniert jetzt.
quelle
Ich hatte dieses Problem mit lokalem var und ich entferne es einfach so:
Problemursachen für geladene Objekte mit demselben Schlüssel. Daher werden wir zuerst dieses Objekt trennen und die Aktualisierung durchführen, um Konflikte zwischen zwei Objekten mit demselben Schlüssel zu vermeiden
quelle
Ich hatte ein ähnliches Problem, nachdem ich 2-3 Tage lang nachgeforscht hatte, dass ".AsNoTracking" entfernt werden sollte, da EF die Änderungen nicht verfolgt und davon ausgeht, dass es keine Änderungen gibt, es sei denn, ein Objekt ist angehängt. Auch wenn wir .AsNoTracking nicht verwenden, weiß EF automatisch, welches Objekt gespeichert / aktualisiert werden soll, sodass Attach / Added nicht verwendet werden muss.
quelle
Verwenden
AsNoTracking()
Sie, wo Sie Ihre Anfrage erhalten.quelle
Ich bin auf diesen Fehler gestoßen, wo
Ich habe Methode B geändert, um eine using-Anweisung zu haben und mich nur auf die lokale db2 zu verlassen . Nach dem:
quelle
Ähnlich wie Luke Puplett sagt, kann das Problem dadurch verursacht werden, dass Sie Ihren Kontext nicht richtig entsorgen oder erstellen.
In meinem Fall hatte ich eine Klasse, die einen Kontext mit dem Namen akzeptierte
ContextService
:Mein Kontextdienst hatte eine Funktion, die eine Entität mithilfe eines instanziierten Entitätsobjekts aktualisiert:
All dies war in Ordnung, mein Controller, auf dem ich den Dienst initialisiert habe, war das Problem. Mein Controller sah ursprünglich so aus:
Ich habe es geändert und der Fehler ging weg:
quelle
Dieses Problem kann auch während gesehen werden ,
ViewModel
umEntityModel
Mapping (unter VerwendungAutoMapper
, etc.) und versuchen , schließencontext.Entry().State
und einecontext.SaveChanges()
solche Verwendung von Block wie unten gezeigt würde das Problem lösen. Bitte beachten Sie, dass diecontext.SaveChanges()
Methode zweimal verwendet wird, anstatt sie direkt danach zu verwenden,if-block
da sie auch in block verwendet werden muss.Hoffe das hilft...
quelle
Hier was ich im ähnlichen Fall gemacht habe.
Diese Situation bedeutet, dass dieselbe Entität bereits im Kontext existiert hat. Das Folgende kann also helfen
Überprüfen Sie zunächst in ChangeTracker, ob sich die Entität im Kontext befindet
Wenn es existiert
quelle
Ich schaffe es, das Problem durch Aktualisieren des Status zu beheben. Wenn Sie die Suche auslösen oder eine andere Abfrageoperation auf demselben Datensatzstatus mit Änderungen aktualisiert wurde, müssen wir den Status auf "Getrennt" setzen, damit Sie Ihre Aktualisierungsänderung auslösen können
quelle
Ich löse dieses Problem mit einem "using" -Block
Hier komme ich auf die Idee https://social.msdn.microsoft.com/Forums/sqlserver/es-ES/b4b350ba-b0d5-464d-8656-8c117d55b2af/problema-al-modificar-en-entity-framework?forum = vcses ist auf Spanisch (suchen Sie nach der zweiten Antwort)
quelle
Sie können eine hinzugefügte Methode wie verwenden;
In vielen Fällen funktioniert dies jedoch nicht, wenn Sie zu diesem Zeitpunkt mehr als ein Modell verwenden möchten, da die Entität bereits mit einer anderen Entität verbunden ist. Zu diesem Zeitpunkt können Sie also die ADDOrUpdate-Entitätsmigrationsmethode verwenden, mit der Objekte einfach von einem zum anderen migriert werden, sodass Sie keinen Fehler erhalten.
quelle
Löschen Sie alle Status
dbContextGlobalERP.ChangeTracker.Entries (). Where (e => e.Entity! = null) .ToList (). ForEach (e => e.State = EntityState.Detached);
quelle