2009-03-25 19 views
3

編集:何かがある可能性がある場合に備え、同じ種類のdatacontextを作成して処理するコードをアクションハンドラが呼び出しますこの動作でコードはMatchUpdateQueueテーブルには触れませんが、私はそれをちょうど言及する必要があります。DeleteOnSubmit LINQ例外 "既に使用中のキーを持つエンティティを追加できません"

ダブル編集:誰もが正解でした!私は質問のほとんどを受けた回答者に答えを出しました。問題を修正すると、別の問題(ハンドラ内に隠されていた)がポップアップすることが許されました。まったく同じ例外がスローされました。うわー!

LINQでアイテムを削除する際に問題が発生します。以下のコードのDeleteOnSubmit呼び出しは、 "既に使用されているキーを持つエンティティを追加できません"というメッセージとともにLINQ例外を発生させます。私はここで何が間違っているのか分からず、壁の上に私を運転し始めている。主キーは整数の自動インクリメントの列であり、データベースキューからアイテムを削除しようとするまでは他の問題はありません。うまくいけば、私はここで痛みを伴い、私でない人のために見つけやすい何かをやっている!

static void Pacman() 
{ 
    Queue<MatchUpdateQueue> waiting = new Queue<MatchUpdateQueue>(); 

    events.WriteEntry("matchqueue worker thread started"); 

    while (!stop) 
    { 
     if (waiting.Count == 0) 
     { 
      /* grab any new items available */ 
      aDataContext db = new aDataContext(); 
      List<MatchUpdateQueue> freshitems = db.MatchUpdateQueues.OrderBy(item => item.id).ToList(); 

      foreach (MatchUpdateQueue item in freshitems) 
       waiting.Enqueue(item); 
      db.Dispose(); 
     } 
     else 
     { 
      /* grab & dispatch waiting item */ 
      MatchUpdateQueue item = waiting.Peek(); 
      try 
      { 
       int result = ActionHandler.Handle(item); 
       if (result == -1) 
        events.WriteEntry("unknown command consumed : " + item.actiontype.ToString(), EventLogEntryType.Error); 

       /* remove item from queue */ 
       waiting.Dequeue(); 

       /* remove item from database */ 
       aDataContext db = new aDataContext(); 
       db.MatchUpdateQueues.DeleteOnSubmit(db.MatchUpdateQueues.Single(i => i == item)); 
       db.SubmitChanges(); 
       db.Dispose(); 
      } 
      catch (Exception ex) 
      { 
       events.WriteEntry("exception while handling item : " + ex.Message, EventLogEntryType.Error); 
       stop = true; 
      } 
     } 

     /* to avoid hammering database when there's nothing to do */ 
     if (waiting.Count == 0) 
      Thread.Sleep(TimeSpan.FromSeconds(10)); 
    } 

    events.WriteEntry("matchqueue worker thread halted"); 
} 

答えて

2

あなたは他の回答が取り付け方に示唆したよう..あなたが他のコンテキストに付けるアイテムを受信した後、元のコンテキストを使用することはできません

db.MatchUpdateQueues.DeleteOnSubmit(db.MatchUpdateQueues.Single(theItem => theItem == item)); 

の効果にだけ注意を何かができますエンティティがシリアル化されていない限りオンになります。

+0

私は持っていた デシベル。MatchUpdateQueues.DeleteOnSubmit(db.MatchUpdateQueues.FirstOrDefault(x => x.id == item.id)); しかし、それは同じ例外を投げたので、私は同じエラーを与える最も簡単なコードに戻りました。 –

+0

私が提供したコードを試してみて、それが例外をスローすると、あなたは例外を投稿できますか? –

+0

コード: db.MatchUpdateQueues.DeleteOnSubmit(db.MatchUpdateQueues.Single(x => x == item)); 例外: 処理中の例外:すでに使用されているキーを持つエンティティを追加できません。 –

0

用途:

aDataContext db = new aDataContext(); 
item = new MatchUpdateQueue { id=item.id }; // <- updated 
db.MatchUpdateQueues.Attach(item); 
db.MatchUpdateQueues.DeleteOnSubmit(item); 
db.SubmitChanges(); 

あなたは、それは、オブジェクトがDBにすでにあることを知らない新しいのDataContextを使用しているので。

+0

私はこれを試しましたが動作しませんでした。同じ例外が出てくる。 –

+0

Quintin Robinsonのように、それはまだ他のデータインターフェイスに接続されています。 itemidだけで新しいItemを作成することができます。 Quintinsメソッドを使用すると、データベースにもう1つのクエリがあります。 – laktak

+0

私はこれに似た何かを試してみましたが、明示的に添付しませんでした。私はちょうどあなたが投稿したとおりに正確に書いてみましたが、アップデートと同じ例外がスローされました –

0

単一のデータ・コンテキストの使用文のwhileループの内部全体をラップしてみてください:

Queue<MatchUpdateQueue> waiting = new Queue<MatchUpdateQueue>(); 
events.WriteEntry("matchqueue worker thread started"); 
while (!stop) 
{ 
    using (var db = new aDataContext()) 
    { 
     if (waiting.Count == 0) 
     { 
     /* grab any new items available */ 
      List<MatchUpdateQueue> freshitems = db.MatchUpdateQueues 
               .OrderBy(item => item.id) 
               .ToList(); 
      foreach (MatchUpdateQueue item in freshitems) 
       waiting.Enqueue(item); 
     } 
     ... 
    } 
} 
+0

スレッド全体に単一のdatacontextを使用すると、同じ例外がスローされます。投稿されたコードの範囲から何かを逃しているに違いないと思われます。なぜなら、それは明確なことではないことです。 –

+0

は、コードが項目を削除しようとしたときに初めて失敗しています。最初の削除の代わりにスレッド:) –

0

は(最初db.Disposeを取り外して)配置。エンティティはデータコンテキストへの参照を保持するため、インスタンスで作業している間はエンティティを破棄したくないため、問題のコードになる可能性があります。これは、接続を必要とする操作を行うときにのみ開いたり閉じたりするため、接続には影響しません。

このような2番目のデータコンテキストを破棄しないでください。例外は、その破棄コードをとにかく呼び出さないためです。 usingキーワードを使用すると、例外が発生したかどうかを確実に破棄することができます。また、データベースからアイテムを取得して削除してください(シリアライズ/デシリアライズ/アタッチを避けるため)。

using (aDataContext db = new aDataContext()) 
{ 
    var dbItem = db.MatchUpdateQueues.Single(i => i.Id == item.Id); 
    db.MatchUpdateQueues.DeleteOnSubmit(dbItem); 
    db.SubmitChanges(); 
} 
+0

の「ループ」は例外プログラムが終了した後、キーワードを使用して使用していませんでした を削除する項目を選択するために、単一のメソッドを使用 をdb.dispose :) 同じ例外がスローされます。 dbcontextsへの参照についても同様の考えがありましたが、問題はないようです。 –

+0

@glipquuxが(クラスレベルで==を実行していた)@glipquuxを更新しましたが、試したときに少し微調整したと思います。私はdbmlの特別な構成を見ていきます。デザイナーでdbエンティティを再追加してみてください。その本当に奇妙なシナリオは、あなたがDeleteOnで失敗するということは確実ですか? – eglasius

0

TEntity(ここのエリア)主キーの型がID列の場合は、これを試してください。 あなたのSPやモデルに変更を加えずにそのままです:

public void InitForm() 
{ 
    'bnsEntity is a BindingSource and cachedAreas is a List<Area> created from dataContext.Areas.ToList() 
    bnsEntity.DataSource = cachedAreas; 
    'A nominal ID 
    newID = cachedAreas.LastOrDefault().areaID + 1; 
    'grdEntity is a GridView 
    grdEntity.DataSource = bnsEntity; 
} 

private void tsbNew_Click(object sender, EventArgs e) 
{ 
    var newArea = new Area(); 
    newArea.areaID = newID++; 
    dataContext.GetTable<Area>().InsertOnSubmit(newArea); 
    bnsEntity.Add(newArea); 
    grdEntity.MoveToNewRecord(); 
} 
関連する問題