• 在linq to sql中处理“更新已被其它用户删除对象”的错误


    在LINQ to SQL中处理“更新已被其它用户删除对象”的错误

     

    在多用户条件下,当你正在修改一条记录时,很有可能另一个用户已把此记录删除。这时,等你修改完毕向数据库提交请求时,会出现“更新已被其它用户删除对象”的错误。

    在LINQ to SQL中,所有本次数据更改冲突都被记录到DataContext.ChangeConflicts集合中。

    通过遍历这个集合,可以知道引发冲突的原因。

    多用户条件下引发数据更改冲突的原因主要有两种:

    1 更新已被其它用户更新的对象

    2 更新已被其它用户删除的对象

    对于上述两种状况,LINQ to SQL采取了不同的处理方法。

    对于第1种情况,LINQ to SQL的DataContext.ChangeConflicts集合对象提供了一个“ResolveAll(更新模式)”方法和“Resolve方法”,最常用的是以下这个形式:     

    try
    {
      db.SubmitChanges(ConflictMode.ContinueOnConflict);//遇到冲突继续执行
    }
    catch (ChangeConflictException)
    {
    foreach (ObjectChangeConflict occ in db.ChangeConflicts)
    {
    var supper = occ.Object as SuppliersInfo;
    occ.Resolve(RefreshMode.KeepChanges);

    或者使用

      //数据更新冲突时,将我的值与其他用户提交的值合并,但我修改过的值拥有最高优先级

            context.ChangeConflicts.ResolveAll(RefreshMode.KeepChanges);

    Console.WriteLine("CompanyName={0}发生并发冲突", supper.CompanyName);
    foreach (MemberChangeConflict s in occ.MemberConflicts)
    {
      Console.WriteLine("字段{0}原始值为{1},数据库中值为{2},新值为{3}",
      s.Member.Name,s.OriginalValue,s.DatabaseValue,s.CurrentValue);
    }
    }
    //处理冲突以后从新提交
    customer.SubmitChanges(ConflictMode.FailOnFirstConflict);//遇到冲突立即终止
    }

    另两种更新冲突处理策略是:

    (1) KeepCurrentValues        即我的值最优先,不管我改过没有,一律用我的值覆盖对应的数据库值来解决此冲突。

    (2)OverwriteCurrentValues    用数据库中的当前值全面取代我现在的值,放弃我做的修改。

    选择好合适策略调用ResolveAll()后,再次调用DataContext.SubmitChanges()方法将会成功更新数据库。

    对于第2种情况(“更新已被其它用户删除的对象”),LINQ to SQL的处理比较另类:

    如果你调用ResolveAll(更新策略)方法,LINQ to SQL仅是简单地将与此对应的冲突对象(ObjectChangeConflict类型)的IsResolve属性设置为True,其结果是LINQ to SQL将不再尝试更新此对象!


    换句话说:你调用ResolveAll(更新策略)方法后,LINQ to SQL认为你不打算处理这个已被其它用户删除的对象,就将其打入“冷宫”,不再理会。

    现在有一个问题:

    如果我想当“更新已被其它用户删除的对象”这一现象出现时,重新向数据库插入此对象,怎么办?

    除非采用序列化方法,否则LINQ to SQL不允许将一个实体对象分离出来。但我们可以克隆一个新对象再将其插入到Table<entity>中。然后,将“更新已被其它用户删除的对象”对应的冲突对象设置为“已解决”状态。

    以下代码片断来自于一个Windows Form应用程序:

         try
                    {
                        context.SubmitChanges(ConflictMode.ContinueOnConflict);
                    }
                    catch (ChangeConflictException)
                    {
                        foreach (ObjectChangeConflict occ in context.ChangeConflicts)
                        {
                            //如果其它用户已删除此实体对象对应的数据库记录

                            if (occ.IsDeleted)
                            {

             //克隆一个新实体对象
                                Book newbook = CloneBook(book);
                                //下次提交时,将插入新对象到Book表中
                                context.Book.InsertOnSubmit(newbook);
                                //通知DataContext不再处理此已被其他用户删除数据库记录的实体对象
                                occ.Resolve();
                            }

                        }

                        //普通的更新冲突,则将我的值与其他用户提交的值合并以解决冲突

                        context.ChangeConflicts.ResolveAll(RefreshMode.KeepChanges);
                        //再次提交
                        context.SubmitChanges(ConflictMode.FailOnFirstConflict);
                        
                      }
                    catch (Exception ex)
                    {

                        MessageBox.Show(ex.Message, "提示信息", MessageBoxButtons.OK, MessageBoxIcon.Error);

                    }

    上述模板代码中,context代表DataContext对象,Book是数据库中的表,LINQ to SQL会为它生成同名的实体类。

    使用LINQ to SQL更新数据库需要有几个注意事项:

    1 当数据表间有主键外键关联时,注意在数据库中将这个关联关系设置为层叠更新与删除。否则, SQL Server会阻止你删除主表记录。除非你一条条地将从表相关记录删除干净后才能删除主表记录。

    对应地,如果你要删除某LINQ to SQL实体类对象,但这个对象还包容着相关联的子实体类对象时,一旦尝试向数据库提交更改,而数据库中没有将这个关联关系设置为层叠更新与删除,则LINQ to SQL将自动回滚操作,一条记录也删除不了!其原因是DataContext.SubmitChange()方法默认启动了一个事务,一出现异常则自动回滚。

    2 克隆有主键外键关联的实体对象时,注意要一并克隆其所包容的子对象,而不要简单地赋值,那是“对象引用复制”而非“对象本身数据的复制”。具体来说,就是new一个新对象,然后逐个地把老对象的值赋给新对象,这个过程可能会递归好几层。最简单的方法是将原对象序列化到一个内存流中,然后从内存流中反序列化以实现对象的完全克隆。

    3 如果需要获取数据库最新数据,可以调用DataContext.Refresh()方法,或者最简单的,直接向数据库发送一个新的LINQ查询,然后更新界面即可(推荐使用数据绑定),后面这个方法最简单可靠。

    多用户环境下数据库的记录的存取冲突是一个令人头痛的问题,需要仔细地处理各种情况,这篇短文期望对大家有点帮助。

    由于本人对LINQ to SQL技术研究与应用不深,因此,如本文有错,敬请朋友指出。

    原文来自: http://blog.csdn.net/bitfan/article/details/4034710

  • 相关阅读:
    spark读取文件时对字符编码的支持
    SparkSQL 数据分页及Top N
    linux下添加hadoop用户
    Window 10 WSL 下hadoop 伪分布式安装
    Window 10下spark shell使用sparksql 时的 “entry in command string: null ls -F C: mphive”问题解决
    spark数据怎样输出到Sql Server
    spark standalone集群模式下一个启动问题的解决
    Ubuntu 上redis 5.0的安装
    apache ambari 部署分布式系统
    Ubuntu18.04 下 Spark 2.4.3 standalone模式集群部署
  • 原文地址:https://www.cnblogs.com/wang726zq/p/2440235.html
Copyright © 2020-2023  润新知