19

使用 进行更改时,当另一个用户更改了该行中的某些数据时SubmitChanges(),LINQ 有时会出现ChangeConflictException异常并显示错误消息Row not found or changed,而没有任何指示存在冲突的行或具有冲突更改的字段。

有没有办法确定哪一行有冲突以及它们发生在哪些字段中,还有没有办法让 LINQ 忽略这个问题并不管怎样都简单地提交数据?

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

4

7 回答 7

24

这是一种查看冲突位置的方法(这是一个 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);
于 2008-08-28T16:16:19.787 回答
19

这些(您可以在部分类中添加到数据上下文中,可能会帮助您了解其工作原理:

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);
        }
    }
}
于 2008-08-28T16:17:33.683 回答
4

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

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

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

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

于 2008-08-28T16:15:58.383 回答
2

当 O/R-Designer 中的列或类型与 SQL 数据库中的列不匹配时,有时也会出现错误“Row not found or changed”,特别是如果一列在 SQL 中可以为空但在 O/中不能为空R-设计师。

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

于 2008-09-17T15:02:37.223 回答
2

感谢@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);

    }
于 2012-09-19T01:00:30.840 回答
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;
    }
于 2019-02-28T07:34:45.623 回答
-1

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

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

您还可以使用:

db.SubmitChanges(ConflictMode.ContinueOnConflict)
于 2008-08-28T21:51:12.383 回答