2011-12-29 54 views
3

我們遇到了一個問題,即使用EF並行插入多個實體。 WCF操作被很多進程調用,以在每次調用中生成一個具有不同分佈式事務的實體。正如我們在sql server profiler中看到的那樣,它會生成以下sql:並行插入多行時死鎖與實體框架

(@0 int,@1 nvarchar(32),@2 datetime2(7),@3 nvarchar(64),@4 int,@5 int,@6 bit) 
insert [dbo].[CommandRequests](
    [CommandId] 
, [DeviceId] 
, [StartDateTime] 
, [EndDateTime] 
, [Parameters] 
, [Caller] 
, [Result] 
, [Priority] 
, [Timeout] 
, [ParentRequestId] 
, [IsSuccessful] 
, [Host]) 
    values (@0, @1, @2, null, null, @3, null, @4, @5, null, @6, null) 

    select [CommandRequestId] 
    from [dbo].[CommandRequests] 
    where @@ROWCOUNT > 0 and [CommandRequestId] = scope_identity() 

因此EF給了我們一個插入,然後再選擇一個。因爲它是並行完成的,它們中的很多會因死鎖而中止。

我們使用EF 4.0,而不是4.1或4.2。

任何想法如何解決這個問題?我已經看到了這個,但它已經很老了: http://social.msdn.microsoft.com/Forums/en-US/adodotnetentityframework/thread/4f634d8f-1281-430b-b664-ec7ca413b387/

回答

2

情況依然如此。 EF沒有任何其他功能來避免這種情況。因此,您的解決方案可以是:

  • 手動同步服務中,以便只有一個呼叫可以在時間插入記錄。這非常醜陋,並且會大大影響吞吐量,但是對於僅執行此單一操作的簡單悲觀鎖定來說,這是非常簡單的解決方案,因此取決於您正在構建的應用程序的類型。
  • 最後看到的選擇是由使用自動生成的ID引起的。 EF需要被通知這個ID。只有插入才能關閉此功能。你可以做的不是在數據庫中使用自動生成的ID,並在應用程序中處理ID生成。您將在DB/EF之外移動Id代,您將完全控制其同步。之後,您將永遠不會再看到此選擇(您還必須爲Id屬性設置StoreGeneratedPatternNone)。例如,您可以實現自定義HiLo Id algorithm
+0

我們正在考慮改變選擇查詢到: 選擇SCOPE_IDENTITY()爲[CommandRequestId] 其中@@ ROWCOUNT> 0 你覺得呢? – 2012-01-03 10:59:21

+0

該查詢是由EF自動生成的。你想如何改變它? – 2012-01-03 11:20:58

+0

您可以使用函數在模型中對其進行更改,我們已經完成了該工作並且它可以工作。 – 2012-01-03 11:36:05

1

我想原因是CommandRequestId不是主鍵。如果你將它設置爲主鍵,你將不會死鎖。我有同樣的問題,當我設置標識列作爲主鍵時,它工作正常。