1

好的,所以你认为你是一个真正的调试器?试试这个:

我有一个 Linq2Sql 项目,突然我们发现偶尔,看似随机,我们会得到同一行的双插入。

我已经继承DataContext和覆盖了SubmitChanges. 在里面,我在调用GetChangeSet()之前和之后都调用了base.SubmitChanges(),并使用文本文件记录器来记录Inserts集合中的对象。另外,我保留对插入对象的引用足够长的时间来记录它们的自动编号 ID。

当双插入发生时,我在数据库中看到,不是每行都插入到MyTableAandMyTableB中,而是每行有两行。SQL Profiler 显示四个插入语句,一个接一个地快速连续:

insert into MyTableA(...
insert into MyTableB(...
insert into MyTableA(...
insert into MyTableB(...

我检查了调试日志,集合中只有两个对象Inserts一个一个。在调用 之后,变更集是空的(应该是)。并且自动编号 ID 显示新插入行的较大值。MyClassAMyClassBbase.SubmitChanges()

另一条有用的信息:在调试模式下单步执行时永远不会发生错误;仅当您在没有断点的情况下运行时。这让我怀疑这与执行速度有关。

我们已经使用同一DataContext个子类一年多了,而且我们以前从未在我们的产品中看到过这种行为。它只发生在MyClassAandMyClassB上。

总结一下:

  1. 从调试日志来看,一切看起来都正常。
  2. 在 SQL Profiler 上,您可以看到正在发生双插入。
  3. 这种行为经常发生,但出乎意料,只发生在提到的两个类中,除了在调试模式下单步执行代码时它从不发生。

编辑 - 新信息: 在我的DataContext子类中,我有以下代码:

try {
  base.SubmitChanges(ConflictMode.ContinueOnConflict);
} catch (ChangeConflictException) {
  // Automerge database values for members that client has not modified.
  foreach (ObjectChangeConflict occ in ChangeConflicts) {
    occ.Resolve(RefreshMode.KeepChanges);
  }
}
// Submit succeeds on second try.
base.SubmitChanges(ConflictMode.FailOnFirstConflict);

MyTableA并且MyTableB两者都有一个强制性的外键OtherTableID引用OtherTable。双重插入发生在ChangeConflictException公共父表更新期间发生的情况下OtherTable

我们闻到气味了,现在...

4

3 回答 3

0

当我之前遇到过这样的问题时,通常是由于多个线程同时执行相同的代码。

您是否尝试过使用lock{}命令来确保插入仅由单个线程使用? MSDN 锁

于 2012-11-19T16:17:39.977 回答
0

看起来这是Linq2Sql中的一个BUG !这是一个可重复的实验:

using (var db1 = new MyDataContext()) {
  var obj1 = db1.MyObjects.Single(x => x.ID == 1);
  obj1.Field1 = 123;
  obj1.RelatedThingies.Add(new RelatedThingy {
                           Field1 = 456,
                           Field2 = "def",
                           });
  using (var db2 = new MyDataContext()) {
    var obj2 = db2.MyObjects.Single(x => x.ID == 1);
    obj2.Field2 = "abc";
    db2.SubmitChanges();
  }
  try {
    db1.SubmitChanges(ConflictMode.ContinueOnConflict);
  } catch (ChangeConflictException) {
    foreach (ObjectChangeConflict occ in ChangeConflicts) {
      occ.Resolve(RefreshMode.KeepChanges);
    }
  }
  base.SubmitChanges(ConflictMode.FailOnFirstConflict);
}

结果:MyObjectID = 1 的记录得到更新,Field1 值为 123,Field2 值为“abc”。并且有两条新的相同记录插入到 RelatedThingy,MyObjectID = 1、Field1 = 456 和 Field2 = "def"。

解释一下

更新:在 Microsoft Connect 上登录后,MS 的好人要求我整理一个小演示项目,突出显示该错误。你不知道吗 - 我无法复制它。它似乎与我项目的一些奇怪的特质有关。没有时间进一步调查,我找到了一个解决方法,无论如何......

于 2012-11-20T13:09:26.983 回答
0

FWIW,我们最近发现我们的重试逻辑存在这个问题SubmitChanges。我们正在做一个InsertAllOnSubmit. 当 aChangeConflictException发生时,我们会Resolve(RefreshMode.KeepChanges,true)在 each 上使用 a 重试ObjectChangeConflict

我们以不同的方式重新完成工作(重试逻辑以重新执行整个事务),这似乎解决了问题。

于 2014-08-05T17:18:28.787 回答