我正在构建一个批处理系统。 Units
批量从20-1000批量。每个Unit
本质上是模型的层次结构(一个主模型和许多子模型)。我的任务涉及将每个模型层次结构作为单个事务保存到数据库(每个层次结构都提交或回滚)。不幸的是EF
由于可能包含数千条记录而无法处理模型层次结构的两个部分。EF竞争的SaveChanges()调用
我所做的解决此问题的方法是设置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
,则会在EF
INSERT
之间出现不同Tasks
之间的死锁。
如果我将IsolationLevel
设置为ReadUncommitted
(我认为会很好,因为我没有做任何SELECTs
)我得到DbConcurrencyExceptions
。
我一直无法找到有关DbConcurrencyExceptions
和Entity Framework
什么好的信息,但我猜测,ReadUncommitted
基本上造成EF
接收信息无效“插入行”。
UPDATE
这里是什么是真正引起我的死锁问题,同时执行插入一些背景资料:
显然,同样的问题在几年前是存在,当Linq到SQL出来了,微软通过改变如何选择scope_identity()来修复它。不知道为什么当Entity Framework出现同样的问题时,他们的立场就变成了SQL Server的问题。
_competing_或_completing_? –