代码之家  ›  专栏  ›  技术社区  ›  ljs TheVillageIdiot

LINQ中的数据冲突

  •  19
  • ljs TheVillageIdiot  · 技术社区  · 16 年前

    使用进行更改时 SubmitChanges() ,林克有时死得很惨 ChangeConflictException 异常并显示错误消息 Row not found or changed

    有没有办法确定哪一行有冲突以及冲突发生在哪些字段中,还有没有办法让LINQ忽略该问题并直接提交数据?

    此外,是否有人知道在以下情况下是否会发生此异常 行中的数据已更改,或者仅当LINQ试图更改的字段中的数据已更改时?

    6 回复  |  直到 13 年前
        1
  •  24
  •   TheSmurf    16 年前

    以下是查看冲突所在位置的方法(这是一个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
  •  19
  •   vzczc    16 年前

    这些(您可以将其添加到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
  •  4
  •   Greg Hurlman    16 年前

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

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

        4
  •  2
  •   Sam    16 年前

    当O/R-Designer中的列或类型与SQL数据库中的列不匹配时,有时也会出现错误“Row not found or changed”(行未找到或更改),尤其是当一列在SQL中可为null,但在O/R-Designer中不可为null时。

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

        5
  •  2
  •   Mark    12 年前

    感谢@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
  •  0
  •   Herman Van Der Blom    6 年前

    未找到或未更改行在大多数情况下是并发问题

    如果其他用户正在更改同一条记录,则会弹出这些错误,因为该记录已被其他用户更改。因此,当您想要消除这些错误时,您应该在应用程序中处理并发性。如果处理好并发性,就不会再出现这些错误。上面的代码示例是处理并发错误的一种方法。缺少的是,在并发错误的情况下,您应该将 refresh 这些方法中的变量,因此 true 更新后需要在屏幕上刷新数据,以便您也可以看到其他用户所做的更新。

        /// <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;
        }
    
        7
  •  -1
  •   liammclennan    16 年前

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

    您还可以使用:

    db.SubmitChanges(ConflictMode.ContinueOnConflict)