Je construis un système de traitement par lots. Les lots de Units
viennent en quantités de 20-1000. Chaque Unit
est essentiellement une hiérarchie de modèles (un modèle principal et de nombreux modèles enfants). Ma tâche consiste à enregistrer chaque hiérarchie de modèle dans une base de données en tant que transaction unique (chaque hiérarchie valide ou annule). Malheureusement, EF
n'a pas pu gérer deux parties de la hiérarchie du modèle en raison de leur potentiel de contenir des milliers d'enregistrements. Ce que j'ai fait pour résoudre ceci est mis en place SqlBulkCopy
pour gérer ces deux modèles potentiellement élevés et laissez EF
gérer le reste des insertions (et l'intégrité référentielle).EF Concurrence SaveChanges() Appels
Lot Loop:
foreach (var unitDetails in BatchUnits)
{
var unitOfWork = new Unit(unitDetails);
Task.Factory.StartNew(() =>
{
unitOfWork.ProcessX(); // data preparation
unitOfWork.ProcessY(); // data preparation
unitOfWork.PersistCase();
});
}
Unité:
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();
}
}
}
}
En ce moment je suis essentiellement coincé entre le marteau et l'enclume. Si je laisse le IsolationLevel
mis à , je reçois des interblocages entre EF
INSERT
déclarations dans différents Tasks
.
Si je mets le IsolationLevel
-ReadUncommitted
(que je pensais que ce serait bien que je ne fais pas SELECTs
) Je reçois DbConcurrencyExceptions
.
Je suis incapable de trouver de bonnes informations sur DbConcurrencyExceptions
et Entity Framework
mais je devine que ReadUncommitted
est essentiellement à l'origine EF
pour recevoir invalides « lignes insérées » informations.
MISE À JOUR
Voici quelques informations de base sur ce qui est réellement la cause de mes problèmes interblocage tout en faisant INSERTS:
Apparemment, ce même problème était présent il y a quelques années quand LINQ to SQL est sorti et Microsoft l'a corrigé en changeant la méthode de sélection de scope_identity(). Vous ne savez pas pourquoi leur position a changé en étant un problème SQL Server lorsque le même problème est apparu avec Entity Framework.
_competing_ ou _completing_? –