2011-12-29 63 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不是主键。如果你将它设置为主键,你将不会死锁。我有同样的问题,当我设置标识列作为主键时,它工作正常。