2010-10-13 12 views
1

J'ai une requête linq en cours d'exécution dans un service Web WCF qui recherche une correspondance et si elle n'est pas trouvée, elle en crée une.LINQ Insérer dans la base de données a entraîné des doublons

mon code ressemble

//ReadCommitted transaction 
    using (var ts = CreateTransactionScope(TransactionScopeOption.RequiresNew)) 
    { 
    Contract contract = db.Contracts.SingleOrDefault(x => x.txtBlah == str); 
    if (contract == null) 
    { 
     contract = new Contract(); 
     contract.txtBlah = str; 
     db.Contracts.InsertOnSubmit(contract); 
     db.SubmitChanges(); 
    } 
    ... 
    db.SubmitChanges(); 
    } 

Le problème est que je reçois des doublons. Je pensais que la transaction aurait verrouillé la base de données pour s'assurer qu'aucun doublon ne serait trouvé (et fournir la possibilité de revenir en arrière). Comment puis-je m'assurer qu'il n'y a pas de doublons?

Répondre

0

Dans une transaction ReadCommited, les données peuvent être modifiées avant la fin de la transaction. Mais vous pouvez utiliser la transaction Serializable qui fera le verrouillage de la table.

db.Connection.Open(); 
using (db.Transaction = db.Connection.BeginTransaction(IsolationLevel.Serializable)) 
{ 
//your code here 
db.Transaction.Commit(); 
} 

Ok, si vous ne voulez pas utiliser Serializable tran alors vous devriez écrire un sproc pour l'insertion atomique, la logique devrait ressembler à ceci SQL dans le code:

db.ExecuteCommand("INSERT INTO Contract (txtBlah) SELECT {0} WHERE NOT EXISTS (SELECT 1 FROM Contract WITH (TABLOCK) WHERE txtBlah={0})", str); 

Note Cela verrouillera également toute la table pendant l'insertion.

En savoir plus sur la façon de créer un sproc sans conditions de course au http://weblogs.sqlteam.com/dang/archive/2007/10/28/Conditional-INSERTUPDATE-Race-Condition.aspx.

+1

qui va bloquer tous les appels autour de cette zone .. puis-je verrouiller uniquement sur les parties d'insertion? alias bloquer les transactions sérialisables à l'intérieur de la transaction readcommitted? – BabelFish

+0

aka peut-on avoir BeginReadCommitTran {DoSomeFunctions; BeginSerializableTran {Insérer; Commettre; } DoMoreFunctions; Commettre; } Si cela a du sens – BabelFish

+0

Ne placez que le select et l'insert dans un tran Serializable ou écrivez-en un sproc. – jomi