Подтвердить что ты не робот

Конфликт данных в LINQ

При внесении изменений с использованием SubmitChanges() LINQ иногда умирает с исключением ChangeConflictException с сообщением об ошибке Row not found or changed, без каких-либо признаков ни строки, которая имеет конфликт, ни полей с конфликтующими изменениями, когда другой пользователь изменил некоторые данные в этой строке.

Есть ли способ определить, в какой строке есть конфликт, и какие поля они происходят, а также есть способ заставить LINQ игнорировать проблему и просто зафиксировать данные независимо?

Кроме того, кто-нибудь знает, возникает ли это исключение, когда какие-либо данные в строке изменились или только когда данные были изменены в поле, которое LINQ пытается изменить?

4b9b3361

Ответ 1

Здесь вы узнаете, где конфликты (это пример MSDN, поэтому вам нужно сильно настроить):

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);
        }
    }
}

Чтобы игнорировать проблему и зафиксировать ее в любом случае:

db.SubmitChanges(ConflictMode.ContinueOnConflict);

Ответ 2

Эти (которые вы могли бы добавить в частичный класс к вашему datacontext, могли бы помочь вам понять, как это работает:

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);
        }
    }
}

Ответ 3

Я получил эту ошибку в обстоятельствах, совершенно не связанных с тем, что описывает сообщение об ошибке.

То, что я сделал, это загрузить объект LINQ через один DataContext, а затем попытался передать SubmitChanges() для объекта через другой DataContext - дал эту ту же ошибку.

Мне нужно было вызвать DataContext.Table.Attach(myOldObject), а затем вызвать SubmitChanges(), работая как шарм.

Стоит посмотреть, особенно если вы считаете, что конфликтов действительно не должно быть.

Ответ 4

Ошибка "Строка не найдена или изменена" также иногда появляется, когда столбцы или типы в O/R-Designer не соответствуют столбцам в базе данных SQL, особенно если один столбец имеет NULLable в SQL, но не имеет значения NULL O/R-Designer.

Итак, проверьте, соответствует ли ваше сопоставление таблиц в O/R-Designer вашей базе данных SQL!

Ответ 5

Благодаря @vzczc. Я нашел пример, который вы очень помогли, но мне нужно было снова вызвать SubmitChanges после разрешения. Вот мои измененные методы - надеюсь, что это кому-то поможет.

    /// <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);

    }

Ответ 6

Те методы не завершены? Не хотите ли вы повторить отправку или обернуть ее в какой-то цикл, иначе не останется гарантии, что изменения будут устранены при конфликте?

Ответ 7

", а также есть способ заставить LINQ игнорировать проблему и просто зафиксировать данные независимо?"

Вы можете установить свойство "Обновить проверку" на своей сущности на "Никогда", чтобы остановить это поле для оптимизации concurrency.

Вы также можете использовать:

db.SubmitChanges(ConflictMode.ContinueOnConflict)