【问题标题】:why is the second DatabaseConflictException being thrown?为什么会引发第二个数据库冲突异常?
【发布时间】:2009-12-15 21:26:03
【问题描述】:

我有一些更新一些行的 linq2sql 东西。 然后,当我提交时,我会这样做:

try
{
    database.SubmitChanges();
}
catch (ChangeConflictException)
{
    database.ChangeConflicts.ResolveAll(RefreshMode.KeepChanges);
    database.SubmitChanges();
}

现在第二次提交(被捕获的那个)再次抛出 ChangeConflictException

这怎么可能?如果可能的话。需要如何进行查询? (我不能再尝试/抓住那个?我什么时候停下来?)

我只想将更改后的值放入数据库。

编辑: 让我重新表述一下这个问题的意图:当我说“ResolveALL(keepchanges)”时,我会认为我会说:“我不在乎..只要使用我的价值观”。相反,它再次抛出相同的异常。

我对这种行为感到惊讶,因为 MSDN 上的示例在第二个 SubmitChanges 周围没有第二次尝试捕获

那么这些异常可以抛出多少次(与列一样多次?),我可以以某种方式完全避免它们(在说 ResolveAll 之后)?

编辑: 我开始赏金之前的最后一次编辑:

按照 1 位评论者的建议,我已经把它做成了一个整洁的循环。但我重试多少次都没关系。从它开始抛出异常的那一刻起,它就永远不会没有异常!所以要么它第一次起作用,要么根本不起作用。

现在我的 linq 更新中有大约 20 或 50 行需要更新(我使用批处理来加快速度)。 是否每个解决方案都只修复 1 列离子 1 行中的一个问题?还是它足够聪明,可以解决它遇到的所有问题?

回顾一下:我刚刚更改的值(只有 1 或 2 列)是无论如何都需要进入数据库的值。我如何使用 linq 来做到这一点(或者我真的应该为此打开一个 SqlConnection 吗?(如果是这样,为什么首先使用 Linq?)

到目前为止我的代码:

 int retry;
 for (retry = 0; retry < 10; retry++)
 {
      try
      {
           database.SubmitChanges();
           //submit succeeded... break loop
           break;
      }
      catch (ChangeConflictException)
      {
           database.ChangeConflicts.ResolveAll(RefreshMode.KeepChanges);

           if (retry > 0)
           {
                Thread.Sleep(retry * 10);  //introduce some wait, to see if this helps
           }
      }

编辑:找到了!

感谢已接受答案中的博客链接,我现在遍历所有冲突并记录它们以查看导致此问题的原因。

我很高兴我做到了,因为事实证明其中一个 DB 字段包含一个触发器,该触发器在某些条件下会更新其他内容。所以我可以随心所欲地解决,每次触发器都会再次触发,从而引发下一次冲突。

这个触发器显然我没有意识到,因为我的数据库管理员把它放在那里以跟踪某事或其他。触发器可能是一个很好的工具,但如果您不了解它们,它们可能会引起严重的头痛!

【问题讨论】:

    标签: c# .net linq-to-sql concurrency


    【解决方案1】:

    当您调用 SubmitChanges() 时,它可能不会处理所有冲突(因此不会全部解决),因为默认行为是在到达第一个冲突时停止。

    尝试改变

    database.SubmitChanges();
    

    database.SubmitChanges(ConflictMode.ContinueOnConflict);
    

    请参阅http://arun-ts.blogspot.com/2009/08/linq-to-sql-concurrency-conflicts.html 了解更多信息。他还在 ResolveAll() 的代码示例中嵌套了两个级别的 try/catch,因此第二次尝试 SubmitChanges() 时,他能够在退出之前记录任何异常。这似乎是一个可以遵循的合理模式。

    【讨论】:

    • 如果函数被称为“ResolveAll”并且他们实际上在技术上这样做,但他们真的不符合人们的期望。我会尝试这种方法,看看是否能解决它。
    • 运气不好。相同的行为。 =^( 我将更深入地阅读博客,并按照他们的建议为我感兴趣的列设置 UpdateCheck 列属性。
    • 在我链接到的页面上,它还显示了一种循环解决冲突的方法(并在每个冲突上调用 Resolve())。我怀疑这两种方法都依赖于 Linq 在您尝试解决它们之前实际上已经确定了所有冲突。听起来 ResolveAll() 并不强制(正如您所说,“我不在乎,只使用我的值”)对数据库进行更改,而是它会处理由 ChangeConflictCollection 建立的每个项目调用 SubmitChanges()。
    • 另一个想法...请参阅下面链接中的代码示例。在调用 Resolve() 之后,似乎不需要再次调用 SubmitChanges()。 msdn.microsoft.com/en-us/library/bb399421.aspx
    • 幸运的是,这个函数的文档非常清楚:msdn.microsoft.com/en-us/library/bb350629.aspx(不是)。无论如何,您的第一个博文,在他的第一个示例中,在解决它们后再次提交更改
    【解决方案2】:

    如果这是您需要不断重试的内容,那么明显的代码重新排序是:

    bool success = false;
    while (!success)
    {
      try
      {
        database.SubmitChanges();
        success = true;
      }
      catch (ChangeConflictException)
      {
        database.ChangeConflicts.ResolveAll(RefreshMode.KeepChanges);
      }
    }
    

    我对数据库知之甚少,所以我不会从理论上讨论您的实际问题是什么,但也许这会解决它:/

    【讨论】:

    • 谢谢...我仍然不确定,为什么异常不断发生。我已经在说明:好的,是的,请全部解决。那么为什么 1 毫秒后它给出了完全相同的异常。谁知道这可能会无限期地继续下去。
    • 尝试解决而不保留更改?
    • 您的系统中正在进行什么样的并发?
    • 我不想使用这个循环,因为它可能是无限的——如果出现无法解决的问题,我宁愿尝试 X 次后失败,也不愿永远走下去......
    猜你喜欢
    • 2020-12-09
    • 1970-01-01
    • 2021-08-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-12-08
    相关资源
    最近更新 更多