【问题标题】:EF Competing SaveChanges() CallsEF 竞争 SaveChanges() 调用
【发布时间】:2011-10-07 14:22:20
【问题描述】:

我正在构建一个批处理系统。 Units 的批次数量为 20-1000 个。每个Unit 本质上是一个模型层次结构(一个主模型和许多子模型)。我的任务涉及将每个模型层次结构作为单个事务保存到数据库中(每个层次结构都提交或回滚)。不幸的是,EF 无法处理模型层次结构的两个部分,因为它们可能包含数千条记录。

我为解决此问题所做的工作是设置 SqlBulkCopy 来处理这两个潜在的高计数模型,并让 EF 处理其余的插入(以及引用完整性)。

批处理循环:

foreach (var unitDetails in BatchUnits)
{
  var unitOfWork = new Unit(unitDetails);
  Task.Factory.StartNew(() =>
    {
      unitOfWork.ProcessX(); // data preparation
      unitOfWork.ProcessY(); // data preparation
      unitOfWork.PersistCase();
    });
}

单位:

class Unit
{
  public PersistCase()
  {
    using (var dbContext = new CustomDbContext())
    {
      // Need an explicit transaction so that 
      // EF + SqlBulkCopy act as a single block
      using (var scope = new TransactionScope(TransactionScopeOption.Required,
        new TransactionOptions() {
          IsolationLevel = System.Transaction.IsolationLevel.ReadCommitted
        }))
      {
        // Let EF Insert most of the records
        // Note Insert is all it is doing, no update or delete
        dbContext.Units.Add(thisUnit);
        dbContext.SaveChanges();  // deadlocks, DbConcurrencyExceptions here

        // Copy Auto Inc Generated Id (set by EF) to DataTables
        // for referential integrity of SqlBulkCopy inserts
        CopyGeneratedId(thisUnit.AutoIncrementedId, dataTables);

        // Execute SqlBulkCopy for potentially numerous model #1
        SqlBulkCopy bulkCopy1 = new SqlBulkCopy(...);
        ...
        bulkCopy1.WriteToServer(dataTables["#1"]);

        // Execute SqlBulkCopy for potentially number model #2
        SqlBulkCopy bulkCopy2 = new SqlBulkCopy(...);
        ...
        bulkCopy2.WriteToServer(dataTables["#2"]);

        // Commit transaction
        scope.Complete();
      }
    }
  }
}

现在我基本上被困在一块石头和一个坚硬的地方之间。如果我将IsolationLevel 设置为ReadCommitted,我会在不同Tasks 中的EF INSERT 语句之间出现死锁。

如果我将IsolationLevel 设置为ReadUncommitted(我认为这很好,因为我没有做任何SELECTs)我得到DbConcurrencyExceptions

我一直无法找到有关 DbConcurrencyExceptionsEntity Framework 的任何有用信息,但我猜测 ReadUncommitted 本质上是导致 EF 收到无效的“插入的行”信息。

更新

以下是有关在执行 INSERTS 时实际导致我的死锁问题的一些背景信息:

http://connect.microsoft.com/VisualStudio/feedback/details/562148/how-to-avoid-using-scope-identity-based-insert-commands-on-sql-server-2005

显然,几年前当 Linq To SQL 出现时,同样的问题也出现了,微软通过更改选择 scope_identity() 的方式来修复它。不知道为什么当实体框架出现同样的问题时,他们的立场变成了 SQL Server 问题。

【问题讨论】:

  • 竞争还是完成

标签: c# .net entity-framework transactions sqlbulkcopy


【解决方案1】:

这个问题在这里解释得很好:http://connect.microsoft.com/VisualStudio/feedback/details/562148/how-to-avoid-using-scope-identity-based-insert-commands-on-sql-server-2005

本质上它是一个内部 EF 问题。我迁移了我的代码以使用 Linq To SQL,它现在可以正常工作了(对于标识值不再使用不必要的 SELECT)。

来自 Linq To Sql 中已修复的完全相同问题的相关引用:

当表有标识列时,Linq to SQL 生成极 插入此类表的 SQL 效率低下。假设表是 订单和身份列是 Id。生成的 SQL 是:

exec sp_executesql N'INSERT INTO [dbo].[Order]([Colum1], [Column2]) 值(@p0,@p1)

SELECT [t0].[Id] FROM [dbo].[Order] AS [t0] WHERE [t0].[Id] = (SCOPE_IDENTITY()) ',N'@p0 int,@p1 int,@p0=124,@p1=432

正如人们所看到的,而不是直接通过使用返回 SCOPE_IDENTITY() 'SELECT SCOPE_IDENTITY()',生成的 SQL 在 使用 SCOPE_IDENTITY() 返回的值的 Id 列。当。。。的时候 表中的记录数很大,这会显着减慢 向下插入。当表被分区时,问题就来了 更糟。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-23
    • 2012-09-30
    相关资源
    最近更新 更多