1

では、あなたは本物のデバッガーだと思いますか? これを試してください:

私は Linq2Sql プロジェクトを持っていますが、突然、時折、一見ランダムに、同じ行の二重挿入が発生することを発見しました。

をサブクラス化DataContextし、オーバーライドしSubmitChangesました。その中で、GetChangeSet()の呼び出しの前後に を呼び出しbase.SubmitChanges()、テキスト ファイル ロガーを使用してInsertsコレクション内のオブジェクトを記録しました。さらに、自動番号付けされた ID を記録するのに十分な時間、挿入されたオブジェクトへの参照を保持します。

MyTableA二重挿入が発生すると、DB で、それぞれ 1 つの行がandに挿入される代わりに、それぞれMyTableB2 つの行があることがわかります。SQL プロファイラーは、4 つの挿入ステートメントを 1 つずつすばやく連続して表示します。

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

Insertsデバッグ ログを確認すると、コレクションには のとのの2のオブジェクトしかありませ。への呼び出し後、変更セットは空です (そうあるべきです)。また、自動付番 IDは、新しく挿入された行の大きい方の値を示します。MyClassAMyClassBbase.SubmitChanges()

もう 1 つの有用な情報:デバッグ モードでステップ実行する場合、バグは発生しません。ブレークポイントなしで実行した場合のみ。これは、実行速度に関係していると思われます。

同じDataContextサブクラスを 1 年以上使用していますが、この種の動作は製品で見たことがありません。と でのみ発生しMyClassAますMyClassB

要約する:

  1. デバッグ ログから、すべてが正しく機能しているように見えます。
  2. SQL プロファイラーでは、二重挿入が発生していることがわかります。
  3. この動作は、デバッグ モードでコードをステップ実行するときに発生しないことを除いて、前述の 2 つのクラスに対してのみ、頻繁に発生しますが、予測できません。

編集 - 新しい情報:サブクラス 内に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

Linq2Sqlのバグのようです! これはあなたのための再現可能な実験です:

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」になります。また、MyObjectID = 1、Field1 = 456、および Field2 = "def" で、RelatedThingy に挿入された2 つの新しい同一のレコードがあります。

それを説明してください!

更新:これを Microsoft Connect に記録した後、MS の親切な人々から、バグを強調する小さなデモ プロジェクトをまとめるように依頼されました。そして、あなたはそれを知りませんか-私はそれを再現できませんでした. 私のプロジェクトの奇妙な特異性に関連しているようです。さらに調査する時間がないので、とにかく回避策を見つけました...

于 2012-11-20T13:09:26.983 に答える
0

以前にこのような問題が発生した場合、通常は複数のスレッドが同時に同じコードを実行していることが原因です。

挿入が単一のスレッドによってのみ使用されていることを確認するために 、lock{}コマンドを使用してみましたか? MSDN ロック

于 2012-11-19T16:17:39.977 に答える
0

FWIW、最近、 の再試行ロジックでこの問題が見つかりましたSubmitChanges。をしていましたInsertAllOnSubmit。aが発生すると、 on eachChangeConflictExceptionで再試行します。Resolve(RefreshMode.KeepChanges,true)ObjectChangeConflict

作業を別の方法でやり直した (トランザクション全体を再実行するロジックを再試行する) と、問題が解決したようです。

于 2014-08-05T17:18:28.787 に答える