私はバッチ処理システムを構築しています。 Units
のバッチは、20〜1000の量で入っています。各Unit
は基本的にモデルの階層(1つのメインモデルと多くの子モデル)です。私の仕事は、各モデル階層をデータベースに単一のトランザクションとして保存することです(各階層がコミットするかロールバックされます)。残念ながら、EF
は、数千のレコードを格納する可能性があるため、モデル階層の2つの部分を処理できませんでした。EF競合するSaveChanges()コール
これを解決するために、SqlBulkCopy
を設定して、これらの2つの可能性の高い高カウントモデルを処理し、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
ステートメントの間にデッドロックが発生します。
私はDbConcurrencyExceptions
を取得する(私はSELECTs
をやっていないよので、私は大丈夫だろうと思っている)ReadUncommitted
にIsolationLevel
を設定した場合。
私はDbConcurrencyExceptions
とEntity Framework
についての良い情報を見つけることができませんされてきたが、私はReadUncommitted
は、本質的に情報無効「挿入された行」を受信するEF
を引き起こしていることを推測しています。
UPDATEはここ
がINSERTSをしながら実際に私のデッドロックの問題を引き起こしているかについて、いくつかの背景情報がある:ときLINQのはへ
どうやらこの同じ問題は数年前に存在していましたSQLが出てきて、Microsoftはscope_identity()の選択方法を変更することでそれを修正しました。 Entity Frameworkで同じ問題が発生したときにSQL Serverの問題になっている理由がわからない。
_competing_または_completing_? –