web-dev-qa-db-ger.com

System.Data.Linq.ChangeConflictException: Zeile nicht gefunden oder geändert

Ich versuche, eine ausgewählte Rasteransicht-Zeile mit LINQ (Nr LINQDataSource) zu löschen.

Wenn die Auswahl geändert wird, ändert sich auch die Detailansicht-Bindung Ich kann einen neuen Eintrag zur Datenbank hinzufügen, aber als ich diesen -Code zu einer Lösch-Schaltfläche im updatePanel hinzugefügt habe, bekam ich eine Ausnahme:

try
{           
    var query = from i in db.QuestionModules 
                where i.QuestionModuleID == QuestionModuleID 
                select i;

    QuestionModule o = query.First();
    db.QuestionModules.DeleteOnSubmit(o);
    db.SubmitChanges();
}

Dies ist die Ausnahme, die ich bekomme:

System.Data.Linq.ChangeConflictException: Row not found or changed. at
System.Data.Linq.ChangeProcessor.SubmitChanges(ConflictMode
failureMode) at
System.Data.Linq.DataContext.SubmitChanges(ConflictMode failureMode)
at System.Data.Linq.DataContext.SubmitChanges() 

Ich hatte dieses Problem seit ungefähr einer Woche, und egal was ich mache, es ist immer noch da, und der Datensatz wird nicht gelöscht.

Irgendwelche Ideen, was zu tun ist?

59
San

OK - es sieht so aus, als ob (in meinem Fall zumindest) die UpdateCheck-Eigenschaft der all nicht-Primärschlüssel-Spalte auf Never in der DBML-Datei gesetzt wurde. Dadurch wurde das Problem "Zeile nicht gefunden oder geändert" sofort behoben.

Angesichts des Gerüchtes, dass Microsoft Linq-To-Sql zugunsten des Entity Frameworks als Mottenkumpel einsetzt, fragt man sich, ob diese Arten von Fehlern behoben werden.

69
Mark

Sie erhalten diesen Fehler möglicherweise, weil eines Ihrer Felder im Linq To SQL-Designer und in der tatsächlichen Datenbank etwas anderes aufweist.

In meinem Fall war dies darauf zurückzuführen, dass eines der Felder in der Datenbank nullfähig und im Designer nicht nullfähig war. Dadurch wurde es auch im Designer nullfähig. Das Problem wurde sofort gelöst.

51
SemMike

Ich habe das gleiche Problem und stieß auf dieses Blog , das im Wesentlichen besagt, dass Linq-To-Sql ein Problem in seiner optimistischen Parallelität hat, wo:

  1. Es werden hochpräzise datetime-Felder verwendet. Die Lösung besteht darin, UpdateCheck auf nie für diese Spalte Ihrer DBML-Datei festzulegen
  2. GridView-Spalten, die auf "unsichtbar" gesetzt sind, greifen auf eine Eigenschaft des Datenobjekts zu (dieser zweite Grund ist nicht sinnvoll, scheint jedoch in diesem Blog allgegenwärtig zu sein).

Ich habe diese Lösungen noch nicht ausprobiert, werde aber hierher zurückkommen, sobald ich es getan habe.

15
Mark

Das Problem könnte auch sein, dass die DBML-Definition der Tabelle nicht mit dem Status der Datenbankdefinition übereinstimmt. Ich habe gerade das DBML-Modell entfernt und es erneut aus der Datenbank eingefügt, und es hat funktioniert.

Hoffe das hilft jemandem.

13

Ich bin um dieses Problem herumgekommen, indem ich sichergestellt habe, dass mein Objekt unmittelbar vor dem Aktualisieren aktualisiert wird. Ich mache das mit der KeepChanges-Option.

    db.Refresh(System.Data.Linq.RefreshMode.KeepChanges, employee);
13
FranticRock

Schien auch für meine Situation zu arbeiten. Ich baute eine in Erinnerung befindliche, nie zuvor eingereichte Zeile mit mehreren Fremdschlüsselbeziehungen zu Zeilen in anderen Tabellen. Das InsertOnSubmit schien zu funktionieren, aber ein nachfolgendes DeleteOnSubmit gab mir den Fehler "Zeile nicht gefunden". Ich habe nicht jedes Feld in der von mir übermittelten Zeile ausgefüllt, daher weiß ich nicht, ob dies etwas damit zu tun hat. Durch das Markieren aller Nicht-Primärschlüssel-Spalten der Haupttabelle wurde die Fehlermeldung beseitigt. 

Ein weiterer Gedanke: Ich nehme an, dass das Markieren der UpdateCheck-Richtlinie einer Spalte als "Nie" bedeutet, dass sie nicht als Grundlage für eine optimistische Konformitätsprüfung verwendet wird. Dies würde bedeuten, dass zwei Benutzer über eine bestimmte Zeile mit unterschiedlichen Daten in einer solchen Spalte schreiben könnten und die Konflikte nicht erkannt würden. Das bedeutet, dass der letzte Benutzer, der die Zeile übergibt, die Werte der vorherigen Benutzerübergabe überschreibt. Ich habe aus verschiedenen Online-Lesern gelernt, dass eine Teillösung darin besteht, die Refresh-Methode unmittelbar vor der Übermittlung zu verwenden, um Änderungen zu synchronisieren. Ohne pesimistische Sperre für die Zeile gibt es natürlich keine Garantie, dass die Zeile nicht immer zwischen Refresh und Submit geändert wird. In den meisten Szenarien mit großen Datenbanken wäre dies jedoch selten.

Update: Bei einer weiteren Überprüfung glaube ich, dass ich ein Szenario entdeckt habe, das sich auf andere auswirken könnte. Ich dachte, ich würde es nur für den Fall mitteilen. Es stellt sich heraus, dass zumindest ein Teil der Probleme, die ich mit SQL LINQ hatte, auf Trigger zurückzuführen ist. Wenn Sie eine Zeile mit SQL LINQ übergeben und Ihr DBA über Trigger verfügt, die dazu dienen, Informationen in einige Spalten dieser Zeile zu schreiben, scheint das SQL LINQ-Modell standardmäßig 'Always' festzulegen, dass die Zeile seit dem letzten Schreibvorgang geändert wurde . Ich übermittelte teilweise aufgefüllte Zeilen, und die Auslöser unseres DBA füllen einige Spalten aus. Wenn ich also versuchte, die Zeile in unserem Code weiter zu modifizieren, wurde ein Änderungskonflikt erkannt, der auf den vom Trigger aufgefüllten Spalten basiert. Ich untersuche jetzt den besten Weg, dies zu tun, aber diese auslösenden Felder so zu ändern, dass die UpdateCheck-Richtlinie "Wann geändert" oder "Nie" für mich funktioniert hat. Ich hoffe es hilft.

6
Travis

Dies ist nur ein Fall von nicht übereinstimmenden Spaltendefinitionen. Entfernen Sie einfach die Tabelle aus .dbmlund fügen Sie sie erneut hinzu. Stellen Sie sicher, dass Sie auto generate value property = true für Spalten ändern, für die automatisch Daten generiert wurden, z. B. Primärschlüssel oder Datetime-Spalten.

3
Nate S.

Ich hatte ähnliche changeconflictexception/"Zeile wurde nicht gefunden oder geändert", wenn eine Zeile aktualisiert wurde

2
Michael9000

Das Problem, das ich hatte, war, dass ich einen DateTime-Typ im .NET-Framework hatte, unser Datenbankfeld jedoch vom Typ DateTime2 war, dh der Datentyp mit höherer Genauigkeit. Wenn wir also Änderungen einreichen, waren die Datumsfelder des Objekts im Vergleich zur Datenbank nur wenige Nanosekunden entfernt, was den Parallelitätsfehler verursachen würde. Dies geschah, als wir zu einer neueren MSSQL-Version migrierten und unsere DateTime-Felder in DateTime2 konvertierten.

Also in unserem Code, wo wir hatten:

    Obj.DateUpdated = DateTime.Now()

Wir haben es geändert in:

    Obj.DateUpdated = DateTime.Parse(DateTime.Now.ToString())

Überprüfen Sie daher Ihre Datentypen, insbesondere Ihre Datumsfelder, wenn Sie diesen Fehler nach einem Upgrade und/oder einer Migration erhalten.

1
dherrin79

Stellen Sie sicher, dass keine Spalten null-Werte in der zugehörigen Tabelle enthalten (d. H. Die zu aktualisierende Tabelle).

1
saltyobi

Wenn Sie die Auswahlmethode für linqdatasource aufrufen und e.result manuell einstellen, müssen Sie auch alle Fremdschlüsselwerte angeben. 

Nichts anderes funktionierte für mich außer diesem.

0
localman

Wie @dherrin79 angedeutet hat, kann dies auf eine Genauigkeitsabweichung zwischen der Datenbank und dem Code zurückzuführen sein. Für mich bestand das Problem darin, dass die Datenbankspalte dezimal (10,2) sein sollte, sie wurde jedoch als dezimal (18,0) erstellt. Dies war für ein Geldfeld, also hätte ich vielleicht den Geldsäulentyp verwenden sollen. 

Also habe ich einen Dollarbetrag gespart, etwa 3,14 USD, aber die Dezimalzahl wurde entfernt. Dies führte dazu, dass der Datenbankwert geändert wurde und nicht mit dem Wert in C # übereinstimmte.

Hoffe das hilft.

0
John Pasquet

Ich wollte nur mein Szenario für jeden hinzufügen, der dieses Problem hat.

Wir verwenden ein benutzerdefiniertes T4 für unsere Linq to SQL-Datenbank. Grundsätzlich haben wir die ursprünglichen Eigenschaften von get/set nur so geändert, dass sie automatisch getrimmt und auf null gesetzt werden.

        get { return _OfficiantNameMiddle.GetValueOrNull(); }
        set 
        {
            value = value.GetValueOrNull();
            if (_OfficiantNameMiddle != value) 
            {
                _IsDirty = true;
                OnOfficiantNameMiddleChanging(value);
                SendPropertyChanging("OfficiantNameMiddle");
                _OfficiantNameMiddle = value;
                SendPropertyChanged("OfficiantNameMiddle");
                OnOfficiantNameMiddleChanged();
            }
        }

Ältere Daten in unserer Datenbank enthielten einige führende/nachgestellte Leerzeichen, sodass bei jeder Parallelitätsprüfung dieser Spalten keine Übereinstimmung gefunden wurde (es wurde der getrimmte Wert mit dem nicht beschnittenen Datenbankwert verglichen). Es war sehr einfach, ein SQL-Profil zu erstellen, die SQL zu übernehmen und die Elemente in der WHERE-Klausel zu kommentieren, bis während der Parallelitätsprüfung eine Zeile zurückgegeben wurde.

Glücklicherweise haben wir ein LastUpdatedOn-Feld in unseren Tabellen, das automatisch über OnValidate (System.Data.Linq.ChangeAction) gesetzt wird.

    partial void OnValidate(System.Data.Linq.ChangeAction action)
    {
        if (action == System.Data.Linq.ChangeAction.Insert)
        {
            CreatedBy = CurrentUserID;
            CreatedOn = DateTime.Now;
            LastUpdatedBy = CreatedBy;
            LastUpdatedOn = CreatedOn;
        }
        else if (action == System.Data.Linq.ChangeAction.Update)
        {
            LastUpdatedBy = CurrentUserID;
            LastUpdatedOn = DateTime.Now;
        }
    }

Um das Problem zu umgehen, setzen wir die Parallelitätsprüfung für alle Spalten außer den Spalten Primärschlüssel und LastUpdatedOn auf Nie. Das hat für uns funktioniert.

0
Jason Butera

Für uns begann das Problem, als wir auf der SQL Server-Seite zu DateTime2 wechselten. Das Markieren von Feldern mit Column (DbType = "DateTime2") hat nicht geholfen. Was also passiert ist, war, dass wir anfänglich auf der Datenbankseite unsere Spalten als DateTime2 (3) als "abwärtskompatibel" mit dem alten DateTime-Typ deklariert haben. Alles schien gut zu funktionieren, bis wir bei der Verwendung von SQL-2 aufgefallen sind -Linq: In den Aktualisierungen dieser Datumsfelder wird die Ausnahme "Zeile nicht gefunden oder geändert" angezeigt. Um die recht lange Geschichte kurz zu machen, bestand die Lösung darin, zwei Dinge zu tun:

  1. Markieren Sie die Spalten mit [Column (DbType = "DateTime2 (3)", CanBeNull = False)], um die Datenbankdeklaration abzugleichen. UND
  2. Schneiden Sie die Präzisionsziffern aus den Eigenschaften in Setters wie folgt ab:

[Column(DbType = "DateTime2(3)", CanBeNull = false)] public DateTime ModifiedAt { get => _modifiedAt; set => _modifiedAt = value.AddTicks(-(value.Ticks % TimeSpan.TicksPerMillisecond)); }

0
Greg Z.

Für mich war es eine Aufzählungsspalte (zugeordnet zu einem Varchar), die das Problem verursacht hat, daher musste ich den Update-Check nie übergeben.

0
tec-goblin

Ich hatte ein ähnliches Problem und obwohl das Löschen und erneute Hinzufügen der DBML-Tabelle/Klasse einigen Benutzern geholfen hat, war es für mich ein bisschen anders, da ich WCF mit getrennter Entität und einer ListView auf dem Client verwende.

Wenn ich die .Attach (Entität) verwendet habe, ist dies fehlgeschlagen - "Zeile nicht gefunden oder geändert" Wenn jedoch .Attach (Entität, Original) verwendet wird, funktioniert sie jedes Mal

public void DeleteTask(Task task)
    {
        TwoDooDataContext db = new TwoDooDataContext();
        db.Tasks.Attach(task,GetTaskByID(task.ID));
        db.Tasks.DeleteOnSubmit(task);
        db.SubmitChanges();
    }
0
Jason

Ich konnte dieses Problem durch Ausführen von databind () auf der Rasteransicht und der Datenquelle während des Updatepanel-Postbacks beheben. 

    protected void UpdatePanel1_Load(object sender, EventArgs e)
    {
        GridView1.DataBind();
        LinqDataSource1.DataBind();
    }

Ich aktualisiere das Updatepanel jedes Mal, wenn sich mein Auswahlindex ändert und die Konflikte gelöst werden konnten.

Hoffe das hilft.

0
Darwin N.

So habe ich es behoben: Zuerst habe ich die Datenbank aktualisiert, dann habe ich die neuen Werte für das Raster als gesetzt

e.Keys["ColumnOne"] ="new value"
e.Keys["ColumnTwo"] ="new value"

All dies wurde unter dem GridView_RowUpdating-Ereignis durchgeführt.

0
AJ17

Unter:

QuestionModule o = query.First();

Sie müssen den folgenden Befehl hinzufügen:

db.QuestionModule.Attach(o);
0
suhad