web-dev-qa-db-fra.com

Pourquoi TransactionScope ne fonctionne-t-il pas avec Entity Framework?

Voir le code ci-dessous. Si j'initialise plus d'un contexte d'entité, j'obtiens l'exception suivante sur le 2nd ensemble de code uniquement. Si je commente le second set cela fonctionne.

{"Le fournisseur sous-jacent a échoué à l'ouverture."}

Inner: {"La communication avec le gestionnaire de transactions sous-jacent a échoué."}

Inner: {"L'erreur HRESULT E_FAIL a été renvoyée à partir d'un appel à un composant COM."}

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

Modifier

Voici une question précédente de moi essayant d'installer MS-DTC. Il semble être activé sur le serveur et le client. Je ne sais pas s'il est correctement configuré. Notez également que l'une des raisons pour lesquelles j'essaie de faire cela est que le code existant dans la variable TransactionScope utilise ADO.NET et Linq 2 Sql ... J'aimerais que ceux-ci utilisent également la même transaction. (Cela semble probablement fou, mais je dois le faire fonctionner si possible).

Comment utiliser TransactionScope en C #?

Solution

_ {Le pare-feu Windows bloquait les connexions à 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();
        }
25
NotDan

Votre coordinateur de transactions distribuées (MS-DTC) ne fonctionne pas correctement pour une raison quelconque. MS-DTC est utilisé pour coordonner les résultats des transactions sur plusieurs ressources hétérogènes, y compris plusieurs connexions SQL.

Jetez un coup d'œil à ce lien pour plus d'informations sur ce qui se passe.

En gros, si vous vous assurez que votre MS-DTC fonctionne et fonctionne correctement, vous ne devriez pas avoir de problèmes avec l’utilisation de 2 connexions ADO.NET, qu’il s’agisse de connexions d’entité ou de tout autre type.

19
Steve Willcock

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

http://forums.Microsoft.com/MSDN/ShowPost.aspx?PostID=580828&SiteID=1&mode=1http://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();
}
19
dreadjr

Ajoutez C:\Windows\msdtc.exe aux exceptions de pare-feu sur le pare-feu et le serveur. Avant de faire cela, j'ai passé des siècles à singer des singes autour de l'ouverture de numéros de port et de plages spécifiques.

5
burnside

Je vais m'en tenir à cela parce que j'ai passé 3 heures avec un collègue hier à déboguer ce problème. Chaque réponse à cette question indique qu'il s'agit toujours d'un problème de pare-feu; Cependant, dans notre cas, ce n'était pas le cas. Espérons que cela épargnera à quelqu'un d'autre la douleur.

Notre situation actuelle est que nous sommes en train de migrer vers Entity Framework. Cela signifie que nous avons des parties du code où, au sein d'une transaction unique, les connexions sont ouvertes à la fois directement à l'aide d'une new SqlConnection(connectionString).Open() et indirectement à l'aide d'un contexte de données EF.

Cela fonctionnait bien dans notre application depuis un moment, mais lorsque nous avons commencé à aller rétrospectivement et à mettre des tests autour du code qui fonctionnait en production, le code exécuté par le lanceur de tests renvoyait cette erreur la première fois que l'objet EF tentait de se connecter. à la base de données après une connexion directe a été établie dans la même transaction.

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

  1. Celui que vous ouvrez manuellement sans argument Application Name=
  2. Un Application Name=EntityFrameworkMUF suffixé généré automatiquement

et il n'est pas possible d'ouvrir deux connexions distinctes dans une même transaction. Le code de production spécifiait un nom d'application. donc cela a fonctionné; le code de test n'a pas. La spécification de l'argument Application Name= a corrigé le bogue pour nous.

4
briantyler

En passant, vous devriez envisager d’utiliser SaveChanges (false) en combinaison avec AcceptChanges () lorsque vous utilisez des transactions explicites comme celle-ci. 

De cette façon, si quelque chose échoue dans SaveChanges (false), ObjectContext n'a pas ignoré vos modifications, vous pouvez donc réappliquer plus tard ou consigner des erreurs, etc.

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

À votre santé

Alex

3
Alex James

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

Dans ce cas, la transaction DOIT être promue en une transaction distribuée. Je suppose que votre problème provient de la configuration de MS DTC (coordinateur de transactions distribuées Microsoft) sur le serveur et/ou le client . Si le serveur n'est pas configuré pour autoriser les connexions distantes pour MSDTC par exemple, vous rencontrerez ce type d'exception. .

vous pouvez vous référer à cette page MS par exemple pour résoudre les problèmes de MSDTC, et Google regorge de sujets/questions de forum à ce sujet.

Maintenant, cela pourrait être autre chose, mais cela ressemble vraiment à un problème de MSDTC.

1
Denis Troller

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

Vous pourriez trouver cette réponse utile.

Comment activer MSDTC sur SQL Server?

0
Davy Landman

Des erreurs similaires se sont produites lors de l'utilisation de DTC lors de la lecture, du traitement et de l'enregistrement des messages dans la file d'attente MQ, dans la base de données SQL 2005 Express Edition. Je n’ai pas suffisamment de temps pour déterminer jusqu’à la fin si 2005 ou une édition Express excatly était à l’origine de ce problème, mais le passage à 2008 Standard a atténué ce comportement particulier.

0