LINQ中的数据冲突

时间:2008-08-28 15:54:56

标签: c# linq linq-to-sql

使用SubmitChanges()进行更改时,LINQ有时会因错误消息ChangeConflictException而导致Row not found or changed异常而死,并且不会显示存在冲突的行或具有更改的字段当另一个用户更改了该行中的某些数据时,它们会发生冲突。

有没有办法确定哪一行存在冲突以及它们出现在哪些字段中?还有一种方法可以让LINQ忽略该问题并简单地提交数据吗?

此外,是否有人知道当行中的任何数据发生更改时,或者仅在LINQ尝试更改的字段中更改了数据时是否发生此异常?

6 个答案:

答案 0 :(得分:23)

以下是查看冲突位置的方法(这是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);

答案 1 :(得分:19)

这些(你可以在你的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);
        }
    }
}

答案 2 :(得分:4)

在与错误消息描述的内容完全无关的情况下,我收到了此错误。

我所做的是通过一个DataContext加载一个LINQ对象,然后尝试通过一个不同的DataContext为该对象提交SubmitChanges() - 给出了完全相同的错误。

我必须做的是调用DataContext.Table.Attach(myOldObject),然后调用SubmitChanges(),就像一个魅力。

值得一看,特别是如果你认为根本不应该有任何冲突。

答案 3 :(得分:2)

当O / R-Designer中的列或类型与SQL数据库中的列不匹配时,有时也会出现“未找到或未更改行”错误,特别是如果一列在SQL中为NULL但在n中不可为空O / R设计师。

因此,检查O / R-Designer中的表映射是否与SQL数据库匹配!

答案 4 :(得分:0)

未找到或更改行通常是并发问题

如果其他用户正在更改同一记录,则会弹出这些错误,因为该记录已被该其他用户更改。因此,当您要消除这些错误时,应处理应用程序中的并发性。如果您能够很好地处理并发性,那么您将再也不会遇到这些错误。上面的代码示例是一种处理并发错误的方法。缺少的是,如果发生并发错误,则应在这些方法中放置一个refresh变量,因此当refreshtrue时,需要在更新后在屏幕上刷新数据,这样您就可以还可以看到其他用户所做的更新。

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

答案 5 :(得分:-1)

“还有一种方法可以让LINQ忽略这个问题并简单地提交数据吗?”

您可以将实体上的“更新检查”属性设置为“从不”,以停止用于乐观并发检查的字段。

您也可以使用:

db.SubmitChanges(ConflictMode.ContinueOnConflict)