1

我在SO上發現了類似的線程,但似乎沒有解決我的確切問題。從多線程調用LINQ-to-SQL中的SubmitChanges()

基本上我使用.NET任務並行庫編寫了一個簡單的生產者/消費者應用程序。生產者在30秒間隔內檢查數據庫表中的記錄。當它找到記錄時,它將它們添加到BlockingQueue。同時,我使用Task.Factory對記錄執行一些操作。

當即將對記錄執行操作時,我想更新記錄上的一個字段以指示它已經在隊列中。這是因爲如果生產者在最後一批仍在處理中時檢查新記錄,它不會將舊條目添加回隊列。

我遇到的這個問題是在多線程的數據上下文中調用SubmitChanges()。我認爲我正在運行競賽條件,但我不確定。

我得到的錯誤是The operation cannot be performed during a call to SubmitChanges.

監製代碼:

BlockingCollection<QueuedMessage> workItems = new BlockingCollection<QueuedMessage>(); 

System.Threading.Timer workItemTimer = new System.Threading.Timer((s) => 
    { 
     var items = repository.GetQueuedMessages(); 

     foreach (var item in items) 
     { 
      workItems.Add(item); 
     } 

    }, null, 0, 30000); 

消費者代碼:

while (workItems.TryTake(out queuedMessage, Timeout.Infinite, new CancellationToken())) 
{ 
    Task.Factory.StartNew((t) => 
     { 
      var messageToSend = (QueuedMessage)t; 

      repository.MarkQueuedMessageAsProcessing(messageToSend.Id); 

      ... 

      Do some stuff with messageToSend 

      .... 

    }, queuedMessage); 
} 

庫代碼:

var entity = DataContext.QueuedMessages.SingleOrDefault(m => m.Id == messageId); 
entity.ProcessingStarted = true; 
DataContext.SubmitChanges(); 

當我跑這與幾個排隊的消息,DataContext.SubmitChanges()將開始拋出異常,與我前面提到的消息,The operation cannot be performed during a call to SubmitChanges.

就像我說的,我覺得是因爲我叫它來自多個線程,但我不知道如何解決此問題。

我試圖改變有問題的行:

ThreadPool.QueueUserWorkItem(s => DataContext.SubmitChanges()); 

但結果都是一樣的。

+0

您的DataContext跨線程共享嗎?如果是這樣,這絕對是你的問題。 – Josh 2012-07-18 19:13:02

+1

嘗試爲存儲庫代碼中的每個更新創建新的數據上下文。 Datacontexts僅適用於單個工作單元 – sga101 2012-07-18 19:13:46

回答

2

您的存儲庫應爲每個更新創建一個新的數據上下文。每一個只能用於a single unit of work。試試這個:

public static void ProcessingStarted(int messageId) 
{ 
    using (DataContext dc = new DataContext()) 
    { 
     var update = dc.QueuedMessages.SingleOrDefault(m => m.Id == messageId); 
     if (update != null) 
     { 
      update.ProcessingStarted = true; 
      dc.SubmitChanges(); 
     } 
    } 
} 
+0

謝謝。略微改變了這一點,但它工作。 – 2012-07-18 19:50:09

0

你需要SubmitChanges嗎?如果生產者每次都使用相同的DataContext實例,那麼它應該返回已經在內存中的那個實例。

如果您在每次檢查時使用新的DataContext,那麼在新的DataContext上執行每個SubmitChanges,但是如果您希望將其作爲修改提交,您可能需要將其從原始上下文中分離並附加到新的上下文中。