Entity Framework: "Die Anweisung zum Speichern, Einfügen oder Löschen des Speichers hat eine unerwartete Anzahl von Zeilen (0) beeinflusst." [geschlossen]


324

Ich verwende Entity Framework, um ein Rastersteuerelement zu füllen. Manchmal, wenn ich Updates mache, erhalte ich die folgende Fehlermeldung:

Die Anweisung zum Speichern, Einfügen oder Löschen des Speichers hat eine unerwartete Anzahl von Zeilen (0) beeinflusst. Entitäten wurden möglicherweise geändert oder gelöscht, seit Entitäten geladen wurden. Aktualisieren Sie ObjectStateManager-Einträge.

Ich kann nicht herausfinden, wie ich das reproduzieren soll. Aber es könnte etwas damit zu tun haben, wie nahe ich die Updates mache. Hat jemand dies gesehen oder weiß jemand, worauf sich die Fehlermeldung bezieht?

Bearbeiten: Leider kann ich das Problem, das ich hier hatte, nicht mehr reproduzieren, da ich mich von diesem Projekt zurückgezogen habe und mich nicht erinnere, ob ich irgendwann eine Lösung gefunden habe, ob ein anderer Entwickler sie behoben hat oder ob ich sie umgangen habe. Daher kann ich keine Antworten akzeptieren.


Ich habe diesen Fehler mit der Einführung einer SQL Server-Sicherheitsrichtlinie auf Zeilenebene erhalten, die Aktualisierungen einer Zeile in einen Zustand ermöglichte, der nicht zurückgelesen werden konnte (ein exklusives FILTER-Prädikat mit einem zulässigen BLOCK-Prädikat) . Bei EntityFramework muss die aktualisierte Zeile nach dem Update zurückgelesen werden, andernfalls wird davon ausgegangen, dass es sich um einen Parallelitätsfehler handelt (zumindest bei Verwendung einer optimistischen Parallelität).
xr280xr

Das Problem könnte ein falsches Scoping für Ihren DBContext stackoverflow.com/questions/49154250/… sein (dieses Beispiel gilt für die ASPNET-Identität, gilt jedoch für jeden Kontext)
Simon_Weaver

Unabhängig vom Kontext dieses Fehlers ist es eine gute Idee, einen Haltepunkt dort zu setzen, wo der Kontext instanziiert wird. Haben Sie erwartet, dass es beim Laden einer Webseite einmal instanziiert wird, aber es erreicht diesen Haltepunkt fünfmal? Dann haben Sie wahrscheinlich eine Rennbedingung. Sehen Request.UriSie sich die tatsächliche Anforderungs-URL an. In meinem Fall hatte ich eine Tracking-Logik, die meine Site traf und den Kontext unnötig aus der Datenbank lud (und gelegentlich auch aktualisierte). Auf der eigentlichen Seite, die ich debuggte, wurden die Daten von einer dummen Tracking-Code-Logik erfasst.
Simon_Weaver

add @ Html.AntiForgeryToken () im Blick
Vikas Sharma

Antworten:


199

Dies ist ein Nebeneffekt einer Funktion, die als optimistische Parallelität bezeichnet wird.

Sie sind sich nicht 100% sicher, wie Sie es in Entity Framework ein- oder ausschalten sollen, aber im Grunde sagt es Ihnen, dass zwischen dem Zeitpunkt, an dem Sie die Daten aus der Datenbank abgerufen haben, und dem Zeitpunkt, an dem Sie Ihre Änderungen gespeichert haben, jemand anderes die Daten geändert hat (was bedeutete, dass Sie gegangen sind um es zu speichern 0 Zeilen wurden tatsächlich aktualisiert). In SQL-Begriffen ist ihre updateAbfragewhere enthält die Klausel den ursprünglichen Wert jedes Felds in der Zeile. Wenn 0 Zeilen betroffen sind, weiß sie, dass ein Fehler aufgetreten ist.

Die Idee dahinter ist, dass Sie am Ende keine Änderung überschreiben, von der Ihre Anwendung nicht wusste, dass sie stattgefunden hat - es ist im Grunde eine kleine Sicherheitsmaßnahme, die .NET bei all Ihren Updates eingeführt hat.

Wenn es konsistent ist, besteht die Wahrscheinlichkeit, dass es innerhalb Ihrer eigenen Logik geschieht (z. B. Sie aktualisieren die Daten tatsächlich selbst in einer anderen Methode zwischen der Auswahl und dem Update), aber es könnte einfach eine Race-Bedingung zwischen zwei Anwendungen sein.


34
Dies geschieht in einer Einzelbenutzerumgebung (auf meinem Entwicklungscomputer), daher glaube ich nicht, dass dies eine Rennbedingung sein könnte. Ich binde an ein benutzerdefiniertes Rastersteuerelement mit einer EntityDataSource, daher bin ich mir nicht sicher, was genau hinter den Kulissen passiert, aber ich habe keinen eigenen zusätzlichen Code, der die Tabellen ändert. Gibt es eine Möglichkeit, diese Parallelitätseinstellung zu ändern?
Strongopinions

3
Ich denke, Sie können dies in Ihrem Entitätsmodell pro Spalte (im Eigenschaftenfenster) tun, aber die Sache ist, dass Sie den Fehler nur nicht sehen und trotzdem nichts aktualisieren. Können Sie die SQL-Befehle anzeigen, die in Ihre Datenbank gelangen (z. B. SQL Server Profiler für MSSQL)? Auf diese Weise können Sie sehen, welches Update generiert wurde, und sollten sehen können, warum dieses Update keine Zeilen beeinflusst.
Fyjham

9
Wenn die Entität über eine Zeitstempeleigenschaft verfügt, stellen Sie sicher, dass diese in Ihrer Ansicht gespeichert ist, und stellen Sie sicher, dass die Entität den Zeitstempel ordnungsgemäß ausfüllt.
anIBMer

Ich hatte eine Zeitstempelspalte und als ich mich damit befasste, funktionierte EF6.1 wie erwartet, danke für den Tipp @anelBMer
JQII

3
Wenn Sie Zeitstempel verwenden, benötigt das zu löschende Objekt den PK-Satz und die RowVersion-Eigenschaft, um es erfolgreich zu aktualisieren! Ich habe die Eigenschaft rowVersion (Zeitstempel) festgelegt, nachdem ich das Objekt an das jeweilige DbSet angehängt habe. Deshalb hat es nicht funktioniert. Gut gemacht!
Legenden

394

Ich bin darauf gestoßen und es wurde dadurch verursacht, dass das ID-Feld (Schlüsselfeld) der Entität nicht festgelegt wurde. Wenn der Kontext zum Speichern der Daten verwendet wurde, konnte er keine ID = 0 finden. Stellen Sie sicher, dass in Ihrer Aktualisierungsanweisung ein Haltepunkt eingefügt ist, und überprüfen Sie, ob die ID der Entität festgelegt wurde.

Aus Paul Belloras Kommentar

Ich hatte genau dieses Problem, weil ich vergessen hatte, die versteckte ID-Eingabe in die .cshtml-Bearbeitungsseite aufzunehmen


3
+1 Ich hatte das gleiche Problem und dies half, die Lösung zu finden. Es stellte sich heraus, dass ich in meinem Bestellmodell [Bind (Exclude = "OrderID")] hatte, was dazu führte, dass der Wert der Entitäts-ID in HttpPost Null war.
Auspuff

2
Genau das habe ich vermisst. Die ID meines Objekts war 0.
Azhar Khorasany

4
@ Html.HiddenFor (model => model.productID) - hat perfekt funktioniert. Ich vermisste die productID auf der EDIT PAGE (MVC RAZOR)
Ravi Ram

2
Ich hatte ein ähnliches Problem, aber mit einer Wendung. Für mich war das Problem, dass ich die SQL-Tabelle nicht richtig eingerichtet hatte. Mein Primärschlüsselfeld war nicht auf automatische Inkrementierung eingestellt. Also würde EF den Datensatz senden, den ich versucht habe, ohne Schlüssel einzufügen, was in Ordnung ist, wenn Sie daran denken, SQL mitzuteilen, dass das Feld ein automatisch inkrementiertes Identitätsfeld ist, das ich vergessen habe: <
Agile Noob

1
Gleiches Problem, jedoch mit einem zusammengesetzten Schlüssel. Einer der Schlüsselwerte wurde nicht festgelegt.
Obaylis

113

Wow, viele Antworten, aber ich habe diesen Fehler bekommen, als ich etwas etwas anderes gemacht habe, das noch niemand erwähnt hat.

Kurz gesagt, wenn Sie ein neues Objekt erstellen und EF mitteilen, dass es mit dem geändert wurde, EntityState.Modifiedwird dieser Fehler ausgegeben, da er noch nicht in der Datenbank vorhanden ist. Hier ist mein Code:

MyObject foo = new MyObject()
{
    someAttribute = someValue
};

context.Entry(foo).State = EntityState.Modified;
context.SaveChanges();

Ja, das scheint dumm zu sein, aber es ist entstanden, weil die fragliche Methode foo, die früher an sie übergeben wurde, früher erstellt wurde, jetzt nur noch someValuean sie übergeben wurde und sich fooselbst erstellt .

Einfache Lösung, gerade Änderung EntityState.Modifiedzu EntityState.Addedändern oder die ganze Linie an:

context.MyObject.Add(foo);

Vielen Dank für die Veröffentlichung. Das war auch mein Problem, ich hatte einen Code kopiert, der den Status auf EntityState.Modified setzte.
ClayRay

23

Ich hatte den gleichen erschreckenden Fehler ... :) Dann wurde mir klar, dass ich vergaß, einen zu setzen

@Html.HiddenFor(model => model.UserProfile.UserId)

für den Primärschlüssel des zu aktualisierenden Objekts! Ich neige dazu, dieses einfache, aber sehr wichtige Ding zu vergessen!

Übrigens: HiddenForist für ASP.NET MVC.


3
Das scheint eine Sicherheitslücke zu sein, um das UserIdin der Form zu speichern , sehr anfällig für Hacker ... dies sollte später vonHttpContext.Current.User.Identity.Name
Serj Sagan

@SerjSagan Sie haben Recht ... aber solange Sie einige Überprüfungen auf der Serverseite durchführen, um die Benutzer-ID und den aktuellen Benutzernamen zu bestätigen, können Sie loslegen.
Leniel Maccaferri

1
Mein Punkt ist, warum Sie das sogar in dem speichern, in dem HiddenForSie es HttpContextsowieso benötigen ... Ich würde diese Eigenschaft überhaupt nicht in das Formular einfügen, was mich zwingen würde, sie immer serverseitig zu füllen ...
Serj Sagan

16

Überprüfen Sie, ob Sie das Attribut "DataKeyNames" in der GridView vergessen haben. Dies ist ein Muss beim Ändern von Daten in GridView

http://msdn.microsoft.com/en-us/library/system.web.ui.webcontrols.gridview.datakeynames.aspx


+1. Perfekte und einfache Lösung für mich. Ich binde GridView an EntityDataSource und habe dies nicht auf meinen Primärschlüssel für das Objekt festgelegt.
Andez

Wir wissen, dass die Kendo-Benutzeroberfläche keinen zusammengesetzten Schlüssel unterstützt, aber falls ich eine neue Spalte hinzugefügt habe, in der meine Schlüssel zu einer zusammengefasst sind, was passiert dann?
Branislav

15

Das Problem wird durch eines von zwei Dingen verursacht:

  1. Sie haben versucht, eine Zeile mit einer oder mehreren Eigenschaften zu aktualisieren Concurrency Mode: Fixed. Die optimistische Parallelität hat verhindert, dass die Daten gespeichert werden. Dh. Einige haben die Zeilendaten zwischen dem Zeitpunkt des Empfangs der Serverdaten und dem Speichern Ihrer Serverdaten geändert.
  2. Sie haben versucht, eine Zeile zu aktualisieren oder zu löschen, aber die Zeile ist nicht vorhanden. Ein weiteres Beispiel für jemanden, der die Daten zwischen dem Abrufen und dem Speichern ändert (in diesem Fall entfernt) ODER versucht, ein Feld zu aktualisieren, das keine Identität ist (dh StoreGeneratedPattern = Computed) und diese Zeile nicht vorhanden ist.

1
Dies kann auch dadurch verursacht werden, dass allen zugewiesenen Objekteigenschaften dieselben Werte wie zuvor zugewiesen wurden.
Serj Sagan

+1 für den 2. Platz. Ich hatte StoreGeneratedPattern = None. Durch Ändern von StoreGeneratedPattern = Identity wurde das Problem behoben. Danke
tkt986

12

Ich habe den gleichen Fehler erhalten, weil ein Teil der PK eine datetime-Spalte war und der eingefügte Datensatz DateTime.Now als Wert für diese Spalte verwendete. Das Entitätsframework fügt den Wert mit Millisekundengenauigkeit ein und sucht dann nach dem Wert, den es gerade eingefügt hat, auch mit Millisekundengenauigkeit. SqlServer hatte den Wert jedoch auf die zweite Genauigkeit gerundet, sodass das Entity-Framework den Millisekunden-Genauigkeitswert nicht finden konnte.

Die Lösung bestand darin, die Millisekunden von DateTime.Now vor dem Einfügen abzuschneiden.


2
Wir hatten das gleiche Problem, außer dass wir in eine DateSpalte mit einem DateTimeWert
einfügten

1
Hier gilt das gleiche. Wir hatten einen Data Warehouse-Datensatz und verwendeten den Zeitstempel als Teil des Schlüssels. Der Zeitstempel im Data Warehouse war eine SQL DateTime, aber der Zeitstempel in C # stimmte nicht überein. Ich habe den SQL-Datentyp in DateTime2 (7) geändert, das EF-Modell aktualisiert und alles wurde behoben.
mmcfly

Das Ändern der Spalte in Datetime2 (7) hat auch bei mir funktioniert. Danke @mmcfly
Dzejms

10

Ich hatte das gleiche Problem und die Antwort von @ webtrifusion half, die Lösung zu finden.

Mein Modell verwendete das Bind(Exclude)Attribut für die ID der Entität, wodurch der Wert der ID der Entität in HttpPost Null war.

namespace OrderUp.Models
{
[Bind(Exclude = "OrderID")]
public class Order
{
    [ScaffoldColumn(false)]
    public int OrderID { get; set; }

    [ScaffoldColumn(false)]
    public System.DateTime OrderDate { get; set; }

    [Required(ErrorMessage = "Name is required")]
    public string Username { get; set; }
    }
}   

Ähnliches Problem, aus Sicherheitsgründen habe ich Bind (include = einige Felder). ID war nicht in der Liste. Außerdem habe ich es als versteckte Eingabe hinzugefügt. Muss etwas gelöscht haben, das von MVC generiert wurde, oder die ID war überhaupt nicht vorhanden. Danke für die Hilfe.
MusicAndCode

10

Ich hatte das gleiche Problem, ich finde heraus, dass es durch die RowVersion verursacht wurde, die null war. Überprüfen Sie, ob Ihre ID und Ihr RowVersion sind nicht null .

Weitere Informationen finden Sie in diesem Tutorial

http://www.asp.net/mvc/tutorials/getting-started-with-ef-using-mvc/handling-concurrency-with-the-entity-framework-in-an-asp-net-mvc-application


Zeilenversion war in meinem Fall null
Prakash

In meinem Fall hatte ich versehentlich das ID-Feld in meinem [Bind (Include = properties)] entfernt. Fügen Sie es wieder hinzu und es hat gut funktioniert.
Caverman

8

Ich bekam diesen Fehler, nachdem ich von Modell zuerst zu Code zuerst gewechselt hatte. Ich habe mehrere Threads, die eine Datenbank aktualisieren, wobei einige möglicherweise dieselbe Zeile aktualisieren. Ich weiß nicht, warum ich bei der Verwendung von model-first kein Problem hatte. Nehmen Sie an, dass ein anderer Standard für die Parallelität verwendet wird.

Um es an einem Ort zu handhaben und die Bedingungen zu kennen, unter denen es auftreten könnte, habe ich meiner DbContext-Klasse die folgende Überladung hinzugefügt:

using System.Data.Entity.Core.Objects;
using System.Data.Entity.Infrastructure;

public class MyDbContext: DbContext {
...
        public int SaveChanges(bool refreshOnConcurrencyException, RefreshMode refreshMode = RefreshMode.ClientWins) {
            try {
                return SaveChanges();
            }
            catch (DbUpdateConcurrencyException ex) {
                foreach (DbEntityEntry entry in ex.Entries) {
                    if (refreshMode == RefreshMode.ClientWins)
                        entry.OriginalValues.SetValues(entry.GetDatabaseValues());
                    else
                        entry.Reload();
                }
                return SaveChanges();
            }
        }
}

Dann SaveChanges(true)wo immer möglich angerufen .


1
OK, alle anderen beschweren sich über das Problem und zeigen, wie sie es auslösen können usw., aber diese Antwort hat eine coole Antwort. Ich verwende ein Modell zum Fortsetzen von Updates (hier keine Schaltfläche zum Speichern, Baby) und habe dieses bei Rasteraktualisierungen erhalten, als der EF-Thread zurückfiel, und es gelöst. Geniale Arbeit, mein guter Name. Du hast mich wie einen Helden aussehen lassen - auf der Schulter von Riesen stehen !!
Tony Trembath-Drake

Hat mir auch geholfen, schauen Sie sich dies für weitere Optionen an
Zvi Redler

7

Sie müssen explizit ein BoundField des Primärschlüssels einfügen. Wenn Sie nicht möchten, dass der Benutzer den Primärschlüssel sieht, müssen Sie ihn über CSS ausblenden:

    <asp:BoundField DataField="Id_primary_key" ItemStyle-CssClass="hidden" 
HeaderStyle-CssClass="hidden" />

Wobei 'versteckt' eine Klasse in CSS ist, deren Anzeige auf 'keine' gesetzt ist.


1
hah, Sie haben mich darauf hingewiesen, dass ich mein verstecktes ID-Feld in ASP.NET MVC gelöscht habe. Danke @Paulo! :)
Tomasz Iniewicz

7

Fügen Sie während der Bearbeitung die ID oder den Primärschlüssel der Entität als verstecktes Feld in die Ansicht ein

dh

      @Html.HiddenFor(m => m.Id)

das löst das Problem.

Wenn Ihr Modell nicht verwendete Elemente enthält, schließen Sie diese ebenfalls ein und senden Sie sie an den Controller


7

Ich bin auch auf diesen Fehler gestoßen. Das Problem wurde durch einen Trigger auf dem Tisch verursacht, auf dem ich speichern wollte. Der Trigger verwendete 'INSTEAD OF INSERT', was bedeutet, dass 0 Zeilen jemals in diese Tabelle eingefügt wurden, daher der Fehler. Glücklicherweise war die Triggerfunktion in einigen Fällen falsch, aber ich denke, es könnte sich um eine gültige Operation handeln, die irgendwie im Code behandelt werden sollte. Hoffe das hilft jemandem eines Tages.


2
Die Entität kann dazu verleitet werden zu glauben, dass Zeilen hinzugefügt wurden, indem eine SELECT-Anweisung (mit der Primärschlüsselspalte) vom Trigger zurückgegeben wird.
Jahu

1
Um den Kommentar von @jahu zu erweitern, musste ich eine tatsächliche ID des neu eingefügten Elements erhalten, das von meinem Trigger zurückgegeben werden soll, und der Spaltenname muss mit der Identitätsspalte der Triggertabelle übereinstimmen (in meinem Fall tatsächlich eine Ansicht, also nicht) Ich habe keine eigene Identität, aber ich hatte den edmx dazu gebracht zu glauben, dass dies der Fall ist. Mein Trigger hat eine Einfügung in eine separate Tabelle durchgeführt, also habe ich gerade diese letzte Zeile zu meinem Trigger hinzugefügt:SELECT SCOPE_IDENTITY() as MyViewId
DannyMeister


In meinem Fall habe ich einen Löschvorgang für Entitäten in einer untergeordneten Sammlung ausgeführt, aber es gab einen Löschauslöser für eine der untergeordneten Entitäten, der dazu führte, dass eine andere der untergeordneten Entitäten gelöscht wurde. Dies verursachte den Fehler, da N - 1 Zeilen betroffen waren, weil der Trigger eine der untergeordneten Entitäten selbst löschte, bevor das Entity Framework versuchte, sie zu löschen.
Skelett

6

Ich bin auf dieses Problem in einer Tabelle gestoßen, in der ein Primärschlüssel fehlte und die eine DATETIME (2, 3) -Spalte hatte (der "Primärschlüssel" der Entität war also eine Kombination aller Spalten) ... Beim Ausführen des Einfügens hatte der Zeitstempel Eine genauere Zeit (2018-03-20 08: 29: 51.8319154), die auf (2018-03-20 08: 29: 51.832) gekürzt wurde, sodass die Suche in Schlüsselfeldern fehlschlägt.


5

Ich hatte auch diesen Fehler. Es gibt Situationen, in denen die Entität möglicherweise nicht über den tatsächlich verwendeten Datenbankkontext informiert ist oder das Modell möglicherweise anders ist. Stellen Sie dazu Folgendes ein: EntityState.Modified; zu EntityState.Added;

Um dies zu tun:

if (ModelState.IsValid)
{
context.Entry(yourModelReference).State = EntityState.Added;
context.SaveChanges();
}

Dadurch wird sichergestellt, dass die Entität weiß, dass Sie den Status verwenden oder hinzufügen, mit dem Sie arbeiten. Zu diesem Zeitpunkt müssen alle richtigen Modellwerte eingestellt werden. Achten Sie darauf, keine Änderungen zu verlieren, die möglicherweise im Hintergrund vorgenommen wurden.

Hoffe das hilft.


1
Du bist ein Gurú! es funktioniert für mich!
Hernaldo Gonzalez

5
  @Html.HiddenFor(model => model.RowVersion)

Meine Zeilenversion war null und musste daher der Ansicht hinzugefügt werden, die mein Problem gelöst hat


Die RowVersion wurde nicht aus der Ansicht an die Bearbeitungsaktion übergeben, und ich habe vergessen, die Modellbindung für RowVersion durchzuführen. Zum Zeitpunkt des Speicherns des Objekts in der Datenbank muss der vorherige Wert der RowVersion zusammen mit dem Objekt für die Parallelitätsprüfung an die Datenbank gesendet werden. Sie machen dumme Fehler, wenn Sie Dinge schneller brauchen!
Dhanuka777

5

Die Linie [DatabaseGenerated(System.ComponentModel.DataAnnotations.DatabaseGeneratedOption.None)]hat in meinem Fall den Trick gemacht:

using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;


[Key]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int? SomeNumber { get; set; }

4

Stellen Sie einfach sicher, dass in Tabelle und Formular sowohl der Primärschlüssel als auch edmx aktualisiert sind.

ich fand , dass Fehler während der Aktualisierung waren in der Regel wegen: - kein Primärschlüssel in der Tabelle - kein Primärschlüssel in der Bearbeitungsansicht / Form (zB @Html.HiddenFor(m=>m.Id)


4

Ich hatte das gleiche Problem. In meinem Fall habe ich versucht, den Primärschlüssel zu aktualisieren, was nicht zulässig ist.


4

Ich habe diesen Fehler sporadisch bei der Verwendung eines async Methode erhalten. Ist nicht passiert, seit ich zu einer synchronen Methode gewechselt bin.

Sporadisch Fehler:

[Authorize(Roles = "Admin")]
[HttpDelete]
[Route("file/{id}/{customerId}/")]
public async Task<IHttpActionResult> Delete(int id, int customerId)
{
    var file = new Models.File() { Id = id, CustomerId = customerId };
    db.Files.Attach(file);
    db.Files.Remove(file);

    await db.SaveChangesAsync();

    return Ok();
}

Funktioniert die ganze Zeit:

[Authorize(Roles = "Admin")]
[HttpDelete]
[Route("file/{id}/{customerId}/")]
public IHttpActionResult Delete(int id, int customerId)
{
    var file = new Models.File() { Id = id, CustomerId = customerId };
    db.Files.Attach(file);
    db.Files.Remove(file);

    db.SaveChanges();

    return Ok();
}

Obwohl dies mein Problem behoben hat, hat es dazu gedient, auf das zugrunde liegende Problem hinzuweisen, das weiter oben in diesem Beitrag über PKs & Row-Versionen erwähnt wurde. Ich hatte es versäumt, eine Schemakarte für eine neue Tabelle hinzuzufügen, was durch die Tatsache, dass die PK die Namenskonventionsregel nicht befolgte, noch komplizierter wurde. <Tabellenname> ID.
Midohioboarder

3

Ich habe diesen Fehler erhalten, als ich einige Zeilen in der Datenbank (in der Schleife) gelöscht und die neuen in derselben Tabelle hinzugefügt habe.

Die Lösung für mich bestand darin, in jeder Schleifeniteration dynamisch einen neuen Kontext zu erstellen


Ich musste das Gleiche tun, immer noch nicht sicher, warum das Problem überhaupt aufgetreten ist, aber das funktioniert.
Jed Grant

3
    public void Save(object entity)
    {
        using (var transaction = Connection.BeginTransaction())
        {
        try
                {
                    SaveChanges();
                    transaction.Commit();
                }
                catch (OptimisticConcurrencyException)
                {
                    if (ObjectStateManager.GetObjectStateEntry(entity).State == EntityState.Deleted || ObjectStateManager.GetObjectStateEntry(entity).State == EntityState.Modified)
                        this.Refresh(RefreshMode.StoreWins, entity);
                    else if (ObjectStateManager.GetObjectStateEntry(entity).State == EntityState.Added)
                        Detach(entity);
                    AcceptAllChanges(); 
                    transaction.Commit();
                }
        }
    }

Können Sie bitte klarstellen, worauf sich "dies" hier bezieht und was ObjectStateManager ist? Ich versuche dies in unserer Basis-Repository-Klasse, erhalte aber Fehler
Naomi

3

Dies ist auch der Fall, wenn Sie versuchen, eine eindeutige Einschränkungssituation einzufügen. Wenn Sie also nur einen Adresstyp pro Arbeitgeber haben können und versuchen, einen zweiten Adresstyp mit demselben Arbeitgeber einzufügen, tritt das gleiche Problem auf .

ODER

Dies kann auch passieren, wenn allen zugewiesenen Objekteigenschaften dieselben Werte wie zuvor zugewiesen wurden.

        using(var db = new MyContext())
        {
            var address = db.Addresses.FirstOrDefault(x => x.Id == Id);

            address.StreetAddress = StreetAddress; // if you are assigning   
            address.City = City;                   // all of the same values
            address.State = State;                 // as they are
            address.ZipCode = ZipCode;             // in the database    

            db.SaveChanges();           // Then this will throw that exception
        }

2

Wenn Sie versuchen, in Ihrer edmx-Datei eine Zuordnung zu einer "Funktion Imports" zu erstellen, kann dies zu diesem Fehler führen. Löschen Sie einfach die Felder zum Einfügen, Aktualisieren und Löschen in den Zuordnungsdetails für eine bestimmte Entität in Ihrem edmx, und es sollte funktionieren. Ich hoffe ich habe es klar gemacht.


2

Ich habe diese Ausnahme beim Anhängen eines Objekts erhalten, das nicht in der Datenbank vorhanden war. Ich hatte angenommen, dass das Objekt aus einem separaten Kontext geladen wurde, aber wenn der Benutzer die Site zum ersten Mal besuchte, wurde das Objekt von Grund auf neu erstellt. Wir haben automatisch inkrementierende Primärschlüssel, damit ich sie ersetzen kann

context.Users.Attach(orderer);

mit

if (orderer.Id > 0) {
    context.Users.Attach(orderer);
}

2

Nun, ich habe das gleiche Problem. Aber das lag an meinem eigenen Fehler. Eigentlich habe ich ein Objekt gespeichert, anstatt es hinzuzufügen. Das war also der Konflikt.


2

Eine Möglichkeit, dieses Problem in einer SQL Server-Umgebung zu beheben, besteht darin, den in Ihrer SqlServer-Kopie enthaltenen SQL-Profiler zu verwenden. Wenn Sie die Express-Version verwenden, erhalten Sie eine kostenlose Kopie von Express Profiler von CodePlex über den folgenden Link:

Express Profiler

Mit Sql Profiler können Sie auf alles zugreifen, was von EF an die DB gesendet wird. In meinem Fall betrug dies:

exec sp_executesql N'UPDATE [dbo].[Category]
SET [ParentID] = @0, [1048] = NULL, [1033] = @1, [MemberID] = @2, [AddedOn] = @3
WHERE ([CategoryID] = @4)
',N'@0 uniqueidentifier,@1 nvarchar(50),@2 uniqueidentifier,@3 datetime2(7),@4 uniqueidentifier',
@0='E060F2CA-433A-46A7-86BD-80CD165F5023',@1=N'I-Like-Noodles-Do-You',@2='EEDF2C83-2123-4B1C-BF8D-BE2D2FA26D09',
@3='2014-01-29 15:30:27.0435565',@4='3410FD1E-1C76-4D71-B08E-73849838F778'
go

Ich habe dies in ein Abfragefenster in SQL Server eingefügt und ausgeführt. Sicher genug, obwohl es lief, waren 0 Datensätze von dieser Abfrage betroffen, daher wurde der Fehler von EF zurückgegeben.

In meinem Fall wurde das Problem durch die CategoryID verursacht.

Es wurde keine CategoryID durch die an die Datenbank gesendete ID EF identifiziert, sodass 0 Datensätze betroffen sind.

Dies war jedoch nicht die Schuld von EF, sondern ein fehlerhafter Null-Koaleszenz "??" Anweisung in einem View Controller, der Unsinn an die Datenebene gesendet hat.


2

Keine der obigen Antworten deckte meine Situation und die Lösung dafür ab.

Code, bei dem der Fehler im MVC5-Controller ausgelöst wurde:

        if (ModelState.IsValid)
        {
            db.Entry(object).State = EntityState.Modified; 
            db.SaveChanges(); // line that threw exception
            return RedirectToAction("Index");
        }

Ich habe diese Ausnahme erhalten, als ich ein Objekt aus einer Bearbeitungsansicht gespeichert habe. Der Grund dafür war, dass ich beim Zurückkehren zum Speichern die Eigenschaften geändert hatte, die den Primärschlüssel für das Objekt bildeten. Daher machte es für EF keinen Sinn, den Status auf "Geändert" zu setzen - es war ein neuer Eintrag, kein zuvor gespeicherter.

Sie können dies lösen, indem Sie entweder A) den Aufruf zum Speichern ändern, um das Objekt hinzuzufügen, oder B) den Primärschlüssel beim Bearbeiten einfach nicht ändern. Ich habe B).


2

Als in der akzeptierten Antwort stand, dass eine Änderung, von der Ihre Anwendung nicht wusste, dass sie stattgefunden hat , nicht überschrieben wird , war ich skeptisch, weil mein Objekt neu erstellt wurde. Aber dann stellte sich heraus, dass es eine gabINSTEAD OF UPDATE, INSERT- TRIGGER an die Tabelle Anhang angehängt war, der eine berechnete Spalte derselben Tabelle aktualisierte.

Sobald ich dies geändert habe, AFTER INSERT, UPDATEhat es gut funktioniert.


2

Dies geschah mir aufgrund einer Nichtübereinstimmung zwischen datetime und datetime2. Seltsamerweise funktionierte es gut, bevor ein Tester das Problem entdeckte. Mein Code First-Modell enthielt eine DateTime als Teil des Primärschlüssels:

[Key, Column(Order = 2)]  
public DateTime PurchasedDate { get; set; } = (DateTime)SqlDateTime.MinValue;

Die generierte Spalte ist eine Datums- / Uhrzeitspalte. Beim Aufrufen von SaveChanges hat EF die folgende SQL generiert:

-- Region Parameters
DECLARE @0 Int = 2
DECLARE @1 Int = 25
DECLARE @2 Int = 141051
DECLARE @3 DateTime2 = '2017-07-27 15:16:09.2630000' --(will not equal a datetime value)
-- EndRegion
UPDATE [dbo].[OrganizationSurvey]
SET [OrganizationSurveyStatusId] = @0
WHERE ((([SurveyID] = @1) AND ([OrganizationID] = @2)) AND ([PurchasedDate] = @3))

Da versucht wurde, eine datetime-Spalte mit einem datetime2-Wert abzugleichen, wurden keine Ergebnisse zurückgegeben. Die einzige Lösung, die ich mir vorstellen konnte, war, die Spalte in datetime2 zu ändern:

[Key, Column(Order = 2, TypeName = "DateTime2")]  
public DateTime PurchasedDate { get; set; } = (DateTime)SqlDateTime.MinValue;

1
Die Seltsamkeit, dass es funktioniert oder nicht funktioniert, hat mit dem zugrunde liegenden Format / der Basis von datetimevs. zu tun datetime2. Im Wesentlichen werden einige Millisekundenwerte zu einer Übereinstimmung ausgewertet, andere nicht. Das gleiche passierte mir und ich wechselte auch zu DateTime2.
xr280xr

+1 Ich wünschte ich könnte +100 für dich. Nachdem ich mich an vielen Orten umgesehen hatte, fand ich dies schließlich und stellte fest, dass ich tatsächlich eine Datetime als Teil meines Primärschlüssels hatte. Ja, das hat es tatsächlich behoben. Ich habe die Spalte auf Datetime2 aktualisiert und es hat funktioniert. Jetzt ist mein Rindfleisch bei Entity Framework, um eine so beschissene Abfrage dafür zu entwickeln, die mich dazu zwingt.
Catchops
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.