2009-04-27 6 views
24

Voir le code ci-dessous. Si j'initialise plus d'un contexte d'entité, alors je reçois l'exception suivante sur le 2ème jeu de code seulement. Si je commente le deuxième set cela fonctionne.Pourquoi TransactionScope ne fonctionne pas avec Entity Framework?

{ "Le fournisseur sous-jacent a échoué sur Ouvrir."}

intérieur: { "Communication avec le gestionnaire de transaction sous-jacente a échoué."}

intérieur: { "Erreur HRESULT E_FAIL a été renvoyé d'un appel à un composant COM. "}

Notez qu'il s'agit d'un exemple d'application et je sais que cela n'a pas de sens de créer deux contextes à la suite. Cependant, le code de production a des raisons de créer plusieurs contextes dans le même TransactionScope, et cela ne peut pas être changé.

Modifier

Voici une précédente question de moi d'essayer de mettre en place MS-DTC. Il semble être activé sur le serveur et le client. Je ne suis pas sûr si elle est configurée correctement. Notez également que l'une des raisons pour lesquelles j'essaye de faire ceci, est que le code existant dans le TransactionScope emploie ADO.NET et Linq 2 Sql ... Je voudrais que ceux-ci emploient la même transaction aussi. (Cela semble probablement fou, mais je dois le faire fonctionner si possible).

How do I use TransactionScope in C#?

Solution

Pare-feu Windows bloque les connexions a été à MS-DTC.

using(TransactionScope ts = new System.Transactions.TransactionScope()) 
     { 
       using (DatabaseEntityModel o = new DatabaseEntityModel()) 
       { 
        var v = (from s in o.Advertiser select s).First(); 
        v.AcceptableLength = 1; 
        o.SaveChanges(); 
       } 

       //-> By commenting out this section, it works 
       using (DatabaseEntityModel o = new DatabaseEntityModel()) 
       { 
        //Exception on this next line 
        var v = (from s1 in o.Advertiser select s1).First();       v.AcceptableLength = 1; 
        o.SaveChanges(); 
       } 
       //-> 

       ts.Complete(); 
     } 

Répondre

18

Votre MS-DTC (coordinateur de transactions distribuées) ne fonctionne pas correctement pour une raison quelconque. MS-DTC est utilisé pour coordonner les résultats des transactions entre plusieurs ressources hétérogènes, y compris plusieurs connexions sql.Pour plus d'informations sur ce qui se passe, consultez this link pour plus d'informations. Fondamentalement, si vous vous assurez que votre MS-DTC est en cours d'exécution et fonctionne correctement, vous ne devriez avoir aucun problème avec l'utilisation de 2 connexions ADO.NET - qu'il s'agisse de connexions d'infrastructure d'entité ou de tout autre type.

+4

Cela fonctionne maintenant. Le pare-feu Windows bloquait les connexions à MS-DTC. – NotDan

19

Vous pouvez éviter d'utiliser une transaction distribuée en gérant votre propre EntityConnection et passer ce EntityConnection à votre ObjectContext. Sinon, vérifiez ceux-ci.

http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=580828&SiteID=1&mode=1 http://forums.microsoft.com/msdn/showpost.aspx?postid=113669&siteid=1&sb=0&d=1&at=7&ft=11&tf=0&pageid=1

EntityConnection conn = new EntityConnection(ConnectionString); 

using (TransactionScope ts = new TransactionScope()) 
{ 
    using (DatabaseEntityModel o = new DatabaseEntityModel(conn)) 
    { 
      var v = (from s in o.Advertiser select s).First(); 
      v.AcceptableLength = 1; 
    } 

    //-> By commenting out this section, it works 
    using (DatabaseEntityModel o = new DatabaseEntityModel(conn)) 
    { 
     //Exception on this next line 
     var v = (from s1 in o.Advertiser select s1).First(); 
       v.AcceptableLength = 1; 
    } 
    //-> 

    ts.Complete(); 
} 
+0

Je ne suis pas seulement en utilisant Entity Framework, donc la réutilisation de l'EntityConnection n'est pas une solution facile non plus (voir edit ci-dessus) – NotDan

+6

+1 pour éviter DTC. Ce n'est pas que ce soit mauvais, c'est juste que les transactions distribuées ne sont pas quelque chose à choisir à la légère. C'est un lien étroit entre l'application et les ressources, ce qui risque d'entraîner une faible disponibilité par conception. –

+0

Vous pouvez également appeler context.Connection.Open() pour le gérer manuellement. Vous n'avez pas besoin de créer l'EntityConnection manuellement –

1

Le problème est que deux différents DataContext créent deux connexions différentes.

Dans ce cas, la transaction doit être promue à une transaction distribuée. Je suppose que votre problème vient de la coniguration de MS DTC (Microsoft Distributed Transaction Coordinator) sur le serveur et/ou le client. Si le serveur n'est pas configuré pour autoriser des connexions distantes pour MSDTC par exemple, vous rencontrerez ce type d'exception. Par exemple, vous pouvez vous référer à this MS page pour le dépannage de problèmes MSDTC, et google est rempli à ras bord d'articles/forum questions à ce sujet. Maintenant, cela peut être quelque chose d'autre, mais cela ressemble vraiment à un problème MSDTC.

+0

Voir ma modification ci-dessus. Je pense que vous avez raison et que j'essaye de configurer MS-DTC ... Je ne sais pas pourquoi ça ne marche pas. – NotDan

0

J'ai écrit une réponse dans une autre question sur la façon de diagnostiquer les échecs des transactions MSDTC.

Vous pourriez trouver cette réponse utile.

How do I enable MSDTC on SQL Server?

3

BTW vous devriez envisager d'utiliser SaveChanges (faux) en combinaison avec AcceptChanges() lorsque vous utiliser des transactions explicites comme celui-ci.

De cette façon, si quelque chose échoue dans SaveChanges (faux), le ObjectContext n'a pas mis au rebut vos modifications afin que vous puissiez réappliquer plus tard ou faire une erreur, etc. journalisation

Voir cet article pour plus d'informations: http://blogs.msdn.com/alexj/archive/2009/01/11/savechanges-false.aspx

Vive

Alex

5

Ajouter C: \ Windows \ msdtc.exe aux exceptions du pare-feu tant sur le pare-feu et serveur. Je passais mon temps à singoter autour de l'ouverture de numéros de port spécifiques et de plages sans succès avant de le faire.

0

J'ai rencontré des erreurs similaires lors de l'utilisation de DTC lors de la lecture des messages à partir de la file d'attente MQ, du traitement et du stockage dans la base de données SQL 2005 Express Edition. Je n'ai pas assez de temps pour enquêter jusqu'à la fin si 2005 ou excatly édition Express a causé ce problème, mais passer à 2008 Standard a disparu ce comportement particulier.

4

Je vais m'en tenir là parce que j'ai passé 3 heures avec un collègue hier à déboguer ce problème. Chaque réponse à ce sujet dit que c'est toujours un problème de pare-feu; Cependant, dans notre cas, ce n'était pas le cas. Espérons que cela épargnera la douleur à quelqu'un d'autre. La situation que nous avons est que nous sommes en train de migrer vers Entity Framework. Cela signifie que nous avons des parties du code où, à l'intérieur d'une seule transaction, les connexions sont ouvertes directement à l'aide d'un new SqlConnection(connectionString).Open() et indirectement en utilisant un contexte de données EF. Cela a fonctionné très bien dans notre application pendant un certain temps, mais lorsque nous avons commencé à effectuer rétrospectivement des tests autour du code qui fonctionnait en production, le code exécuté par le coureur de test a continué à lancer cette erreur la première fois. objet essayé de se connecter à la base de données après une connexion directe avait été faite dans la même transaction.

La cause du bug finalement avéré être que si vous ne fournissez pas un argument Application Name= à votre chaîne de connexion, Entity Framework ajoute un par défaut (quelque chose comme EntityFrameworkMUF).Cela signifie que vous avez deux connexions distinctes dans votre pool de connexion:

  1. celui que vous ouvrez manuellement sans argument Application Name=
  2. Un produit automatiquement un suffixé Application Name=EntityFrameworkMUF

et il est impossible de ouvrir deux connexions distinctes à l'intérieur d'une seule transaction. Le code de production a spécifié un nom d'application; d'où cela a marché; le code de test n'a pas. La spécification de l'argument Application Name= a corrigé le bug pour nous.

+0

Mon problème était encore plus précis, une connectiontring utilisait 'App = EntityFramework', l'autre utilisait' Application Name = EntityFramework'. La meilleure chose à faire, si c'est votre problème, est de copier la chaîne de connexion d'un contexte et de la passer en paramètre lorsque vous créez la seconde. –

Questions connexes