Frage

Bei Änderungen mit SubmitChanges(), LINQ stirbt manchmal mit a ChangeConflictException Ausnahme mit der Fehlermeldung Row not found or changed, ohne Angabe der Zeile, in der der Konflikt vorliegt, oder der Felder mit Änderungen, die im Konflikt stehen, wenn ein anderer Benutzer einige Daten in dieser Zeile geändert hat.

Gibt es eine Möglichkeit, festzustellen, in welcher Zeile ein Konflikt vorliegt und in welchen Feldern er auftritt, und gibt es auch eine Möglichkeit, LINQ dazu zu bringen, das Problem zu ignorieren und die Daten trotzdem einfach festzuschreiben?

Weiß außerdem jemand, ob diese Ausnahme wann auftritt? beliebig Daten in der Zeile haben sich geändert, oder nur, wenn Daten in einem Feld geändert wurden, das LINQ zu ändern versucht?

War es hilfreich?

Lösung

So können Sie sehen, wo die Konflikte liegen (dies ist ein MSDN-Beispiel, Sie müssen also umfangreiche Anpassungen vornehmen):

try
{
    db.SubmitChanges(ConflictMode.ContinueOnConflict);
}
catch (ChangeConflictException e)
{
    Console.WriteLine("Optimistic concurrency error.");
    Console.WriteLine(e.Message);
    Console.ReadLine();
    foreach (ObjectChangeConflict occ in db.ChangeConflicts)
    {
        MetaTable metatable = db.Mapping.GetTable(occ.Object.GetType());
        Customer entityInConflict = (Customer)occ.Object;
        Console.WriteLine("Table name: {0}", metatable.TableName);
        Console.Write("Customer ID: ");
        Console.WriteLine(entityInConflict.CustomerID);
        foreach (MemberChangeConflict mcc in occ.MemberConflicts)
        {
            object currVal = mcc.CurrentValue;
            object origVal = mcc.OriginalValue;
            object databaseVal = mcc.DatabaseValue;
            MemberInfo mi = mcc.Member;
            Console.WriteLine("Member: {0}", mi.Name);
            Console.WriteLine("current value: {0}", currVal);
            Console.WriteLine("original value: {0}", origVal);
            Console.WriteLine("database value: {0}", databaseVal);
        }
    }
}

Damit das Problem ignoriert und trotzdem ein Commit durchgeführt wird:

db.SubmitChanges(ConflictMode.ContinueOnConflict);

Andere Tipps

Diese (die Sie in einer Teilklasse zu Ihrem Datenkontext hinzufügen können) helfen Ihnen möglicherweise zu verstehen, wie das funktioniert:

public void SubmitKeepChanges()
{
    try
    {
        this.SubmitChanges(ConflictMode.ContinueOnConflict);
    }
    catch (ChangeConflictException e)
    {
        foreach (ObjectChangeConflict occ in this.ChangeConflicts)
        {
            //Keep current values that have changed, 
//updates other values with database values

            occ.Resolve(RefreshMode.KeepChanges);
        }
    }
}

public void SubmitOverwrite()
{
    try
    {
        this.SubmitChanges(ConflictMode.ContinueOnConflict);
    }
    catch (ChangeConflictException e)
    {
        foreach (ObjectChangeConflict occ in this.ChangeConflicts)
        {
            // All database values overwrite current values with 
//values from database

            occ.Resolve(RefreshMode.OverwriteCurrentValues);
        }
    }
}

public void SubmitKeepCurrent()
{
    try
    {
        this.SubmitChanges(ConflictMode.ContinueOnConflict);
    }
    catch (ChangeConflictException e)
    {
        foreach (ObjectChangeConflict occ in this.ChangeConflicts)
        {
            //Swap the original values with the values retrieved from the database. No current value is modified
            occ.Resolve(RefreshMode.KeepCurrentValues);
        }
    }
}

Ich habe diesen Fehler unter einem Umstand erhalten, der überhaupt nichts mit der Beschreibung der Fehlermeldung zu tun hat.

Ich habe ein LINQ-Objekt über einen DataContext geladen und dann versucht, SubmitChanges() für das Objekt über einen anderen DataContext zu senden – was genau den gleichen Fehler ergab.

Was ich tun musste, war DataContext.Table.Attach(myOldObject) aufzurufen und dann SubmitChanges() aufzurufen, was wie ein Zauber funktionierte.

Einen Blick lohnt sich, vor allem wenn man der Meinung ist, dass es eigentlich gar keine Konflikte geben sollte.

Der Fehler „Zeile nicht gefunden oder geändert“ wird manchmal auch angezeigt, wenn die Spalten oder Typen im O/R-Designer nicht mit den Spalten in der SQL-Datenbank übereinstimmen, insbesondere wenn eine Spalte in SQL NULL-fähig ist, im O/R-Designer jedoch nicht nullbar ist. R-Designer.

Prüfen Sie also, ob Ihre Tabellenzuordnung im O/R-Designer zu Ihrer SQL-Datenbank passt!

Danke an @vzczc.Ich fand das Beispiel, das Sie gegeben haben, sehr hilfreich, aber ich musste SubmitChanges nach der Lösung erneut aufrufen.Hier sind meine modifizierten Methoden – ich hoffe, es hilft jemandem.

    /// <summary>
    /// Submits changes and, if there are any conflicts, the database changes are auto-merged for 
    /// members that client has not modified (client wins, but database changes are preserved if possible)
    /// </summary>
    public void SubmitKeepChanges()
    {
        this.Submit(RefreshMode.KeepChanges);
    }

    /// <summary>
    /// Submits changes and, if there are any conflicts, simply overwrites what is in the database (client wins).
    /// </summary>
    public void SubmitOverwriteDatabase()
    {
        this.Submit(RefreshMode.KeepCurrentValues);
    }

    /// <summary>
    /// Submits changes and, if there are any conflicts, all database values overwrite
    /// current values (client loses).
    /// </summary>
    public void SubmitUseDatabase()
    {
        this.Submit(RefreshMode.OverwriteCurrentValues);
    }

    /// <summary>
    /// Submits the changes using the specified refresh mode.
    /// </summary>
    /// <param name="refreshMode">The refresh mode.</param>
    private void Submit(RefreshMode refreshMode)
    {
        bool moreToSubmit = true;
        do
        {
            try
            {
                this.SubmitChanges(ConflictMode.ContinueOnConflict);
                moreToSubmit = false;
            }
            catch (ChangeConflictException)
            {
                foreach (ObjectChangeConflict occ in this.ChangeConflicts)
                {
                    occ.Resolve(refreshMode);
                }
            }
        }
        while (moreToSubmit);

    }

Wenn die Zeile nicht gefunden oder geändert wurde, handelt es sich in den meisten Fällen um ein Problem mit der Parallelität

Wenn ein anderer Benutzer denselben Datensatz ändert, werden diese Fehler angezeigt, da der Datensatz bereits von diesem anderen Benutzer geändert wurde.Wenn Sie diese Fehler beseitigen möchten, sollten Sie die Parallelität in Ihrer Anwendung berücksichtigen.Wenn Sie gut mit Parallelität umgehen, werden diese Fehler nicht mehr auftreten.Die oben genannten Codebeispiele sind eine Möglichkeit, Parallelitätsfehler zu behandeln.Was fehlt, ist, dass Sie im Falle eines Parallelitätsfehlers eine eingeben sollten refresh Variable in diesen Methoden, also wann refresh Ist true Die Daten müssen nach der Aktualisierung auf dem Bildschirm aktualisiert werden, damit Sie auch die vom anderen Benutzer vorgenommene Aktualisierung sehen können.

    /// <remarks>
    ///     linq has optimistic concurrency, so objects can be changed by other users, while
    ///     submitted keep database changes but make sure users changes are also submitted
    ///     and refreshed with the changes already made by other users.
    /// </remarks>
    /// <returns>return if a refresh is needed.</returns>
    public bool SubmitKeepChanges()
    {
        // try to submit changes to the database.
        bool refresh = false;
        try
        {
            base.SubmitChanges(ConflictMode.ContinueOnConflict);
        }

        /* 
         * assume a "row not found or changed" exception, if thats the case:
         * - keep the database changes already made by other users and make sure
         * - this users changes are also written to the database
         */
        catch (ChangeConflictException)
        {
            // show where the conflicts are in debug mode
            ShowConflicts();

            // get database values and combine with user changes 
            base.ChangeConflicts.ResolveAll(RefreshMode.KeepChanges);

            // submit those combined changes again to the database.
            base.SubmitChanges();

            // a refresh is needed
            refresh = true;
        }

        // return if a refresh is needed.
        return refresh;
    }

„Und gibt es auch eine Möglichkeit, LINQ dazu zu bringen, das Problem zu ignorieren und die Daten trotzdem einfach festzuschreiben?“

Sie können die Eigenschaft „Aktualisierungsprüfung“ Ihrer Entität auf „Nie“ setzen, um zu verhindern, dass dieses Feld für die Prüfung auf optimistische Parallelität verwendet wird.

Sie können auch Folgendes verwenden:

db.SubmitChanges(ConflictMode.ContinueOnConflict)
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top