2009-08-25 7 views
3

Nous utilisons Entity Framework et exécutons des tests unitaires dans une étendue de transaction. Nous avions l'origine de l'erreur dans le titre.Impossible d'accéder à un objet éliminé. Transaction

J'ai réussi à isoler le problème quelque chose.

using (TransactionScope scope1 = new TransactionScope()) 
{ 
    using (TransactionScope scope2 = new TransactionScope()) 
    { 
      // Here there is no code 
    } 

    using (Entities se = new Entities()) 
    { 
     EntityConnection entityConnection = (EntityConnection)se.Connection; 
     DbConnection storeConnection = entityConnection.StoreConnection; 

     storeConnection.Open(); // On this line the error occurs 

      // Some code that runs a stored procedure 
    } 
} 

L'erreur que nous sommes en train de se déplacer est « L'opération est valable pour l'état de la transaction .. »

Si je retire SCOPE2 de transaction, tout fonctionne bien.

Si je marque la portée 2 comme une transaction ambiante, cela fonctionne également très bien.

Répondre

6

Vous créez SCOPE2 sans paramètre TransactionScopeOption explicite, ce qui donne une valeur par défaut de TransactionScopeOption.Required, voir la section Remarques au sein TransactionScope Constructor

Ce constructeur crée une nouvelle portée de transaction avec la transaction option d'étendue égale à Champs obligatoires. Cette signifie qu'une transaction est requise par la nouvelle portée et la transaction ambiante est utilisée s'il en existe déjà une . Sinon, il crée une nouvelle transaction avant d'entrer dans la portée.

Dans votre exemple une TransactionScope ambiante existe en effet déjà (scope1), par conséquent la nouvelle imbriquée TransactionScope (scope2) avec le paramètre implicite TransactionScopeOption.Required est d'utiliser la transaction ambiante plutôt que de créer une nouvelle transaction elle-même.

Cependant, la sémantique de transaction implicites de scope2 sont toujours en place, par conséquent, la transaction ambiante existante créée par scope1 est s'avorté parce que vous n'êtes pas appeler Complete à la fin de scope2:

A défaut d'appeler cette méthode annule la transaction , parce que la transaction gestionnaire interprète cela comme un échec du système ou équivalent à une exception jeté dans le cadre de la transaction

Bien sûr, le problème se aways immédiatement si vous supprimez scope2 ou de modifier sa sémantique à TransactionScopeOption.RequiresNew (ce qui signifie « Une nouvelle transaction est toujours créée pour le champ d'application. »), parce que la transaction ambiante existante créée par scope1 ne sera pas affecté plus.

Voir Implementing an Implicit Transaction using Transaction Scope pour plus de détails à ce sujet.

+0

Merci, qui fixe, je manquais le scope2.complete() –

0

Que diriez-vous de cette syntaxe, c'est assez similaire, Scope2 est terminé et disposé de plus tard.

Je vois également par intermittence l'erreur "Impossible d'accéder à un objet" Transaction " Est-ce parce que j'aurais dû créer les deux avec TransactionScopeOption.RequiresNew au lieu de TransactionScopeOption.Required?

TransactionOptions rootOptions = new TransactionOptions(); 
    rootOptions.IsolationLevel = IsolationLevel.ReadCommitted; 
    OtherObject.Scope2 = new TransactionScope(TransactionScopeOption.Required, rootOptions); 

    TransactionOptions options = new TransactionOptions(); 
    options.IsolationLevel = IsolationLevel.ReadCommitted; 
    options.Timeout = getTransactionTimeout(); 
    using (TransactionScope scope = new TransactionScope(TransactionScopeOption.Required, options)) 
       { 

           ............. 
        scope.Complete(); 
       } 
+0

Salut, je vois aussi que intermitent « ne peut pas accéder à un objet disposé Nom de l'objet:.. « TransactionScope » Avez-vous fixer également? – Tasio

Questions connexes