2009-04-27 22 views
24

Vea el código a continuación. Si inicializo más de un contexto de entidad, entonces obtengo la siguiente excepción en el 2º conjunto de código solo. Si comento el segundo set, funciona.¿Por qué TransactionScope no funciona con Entity Framework?

{ "El proveedor subyacente no se ajustó en Abrir."}

interno: { "La comunicación con el administrador de transacciones subyacente ha fallado."}

interno: { "Error HRESULT E_FAIL ha sido devuelto desde una llamada a un componente COM. "}

Tenga en cuenta que esta es una aplicación de muestra y sé que no tiene sentido crear 2 contextos en una fila. Sin embargo, el código de producción tiene motivos para crear contextos múltiples en el mismo TransactionScope, y esto no puede modificarse.

Editar

Aquí es una pregunta anterior de mí tratando de establecer MS-DTC. Parece estar habilitado tanto en el servidor como en el cliente. No estoy seguro de si está configurado correctamente. También tenga en cuenta que una de las razones por las que estoy tratando de hacer esto es que el código existente en el TransactionScope usa ADO.NET y Linq 2 Sql ... Me gustaría que también usen la misma transacción. (Eso probablemente suene loco, pero necesito hacerlo funcionar si es posible).

How do I use TransactionScope in C#?

Solución

Firewall de Windows estaba bloqueando las conexiones con 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(); 
     } 

Respuesta

18

Su MS-DTC (coordinador de transacciones distribuidas) no funciona correctamente por algún motivo. MS-DTC se utiliza para coordinar los resultados de transacciones entre múltiples recursos heterogéneos, incluidas múltiples conexiones sql.

Eche un vistazo a this link para obtener más información sobre lo que está sucediendo.

Básicamente, si se asegura de que su MS-DTC se esté ejecutando y funcionando correctamente, no debería tener problemas con el uso de 2 conexiones ADO.NET, ya sean conexiones de entidades de marco o de otro tipo.

+4

Esto funciona ahora. Windows Firewall estaba bloqueando las conexiones a MS-DTC. – NotDan

19

Puede evitar el uso de una transacción distribuida por la gestión de su propia EntityConnection y pasando este EntityConnection a su ObjectContext. De lo contrario, echa un vistazo a estos.

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

No solo estoy usando Entity Framework, por lo que reutilizar EntityConnection tampoco es una solución fácil (ver la edición anterior) – NotDan

+6

+1 para evitar el DTC. No es que sea malo, es solo que las transacciones distribuidas no son algo para elegir a la ligera. Se trata de una vinculación estrecha entre la aplicación y los recursos, lo que pone en riesgo la baja disponibilidad por diseño. –

+0

También puede llamar context.Connection.Open() para administrarlo manualmente. No necesita crear EntityConnection manualmente –

1

El problema es que 2 DataContext diferente crear efectivamente dos conexiones diferentes.

En ese caso, la transacción TIENE que ser promovida a una transacción distribuida. Supongo que su problema proviene de la configuración de MS DTC (Coordinador de transacciones distribuidas de Microsoft) en el servidor y/o el cliente. Si el servidor no está configurado para permitir conexiones remotas para MSDTC, por ejemplo, encontrará ese tipo de excepción.

Por ejemplo, puede consultar this MS page para solucionar problemas de MSDTC, y Google está repleto de preguntas sobre artículos/foros al respecto.

Ahora, podría ser otra cosa, pero realmente parece que es un problema de MSDTC.

+0

Ver mi edición superior. Creo que tienes razón y estoy tratando de obtener la configuración de MS-DTC ... No estoy seguro de por qué no está funcionando. – NotDan

3

Por cierto debe considerar el uso SaveChanges (falsas) en combinación con AcceptChanges() cuando el uso de transacciones explícitos como este.

De esta forma si algo falla en SaveChanges (falsas), el ObjectContext no ha descartado cambios para que pueda volver a aplicar más tarde, o hacer algún registro de errores, etc.

Ver este post para más información: http://blogs.msdn.com/alexj/archive/2009/01/11/savechanges-false.aspx

Saludos

Alex

5

Añadir C: \ Windows \ msdtc.exe a las excepciones de firewall en tanto el servidor de seguridad y el servidor. Pasé muchísimo tiempo mondando alrededor de números de puertos específicos y rangos sin resultado antes de hacerlo.

0

Tuve errores similares cuando usé DTC al leer mensajes de la cola MQ, procesarlos y almacenarlos en la base de datos SQL 2005 Express Edition. No tengo suficiente tiempo para investigar hasta el final si 2005 o excatly Express edition causaron este problema, pero al cambiar a 2008 Standard se desvaneció ese comportamiento en particular.

4

Voy a pegar esto aquí porque pasé 3 horas con un colega ayer depurando este problema. Cada respuesta que rodea esto dice que este es siempre un problema de firewall; sin embargo, en nuestro caso no fue así. Espero que esto le ahorre a alguien más el dolor.

La situación que tenemos es que actualmente estamos en el proceso de migración al Entity Framework. Eso significa que tenemos partes del código donde dentro de una sola transacción las conexiones se abren directamente usando un new SqlConnection(connectionString).Open() e indirectamente usando un contexto de datos EF.

Esto ha funcionado bien en nuestra aplicación durante un tiempo, pero cuando comenzamos a retrospectivamente ir y poner pruebas alrededor del código que funcionaba en producción, el código ejecutado desde el corredor de prueba siguió arrojando este error la primera vez objeto intentado conectarse a la base de datos después de se ha realizado una conexión directa en la misma transacción.

La causa del error finalmente resultó ser que si no proporciona un argumento Application Name= en su cadena de conexión, Entity Framework agrega uno por defecto (algo así como EntityFrameworkMUF).Esto significa que tiene dos conexiones distintas en su conjunto de conexiones:

  1. la que se abre manualmente sin Application Name= argumento
  2. Un genera automáticamente un sufijo Application Name=EntityFrameworkMUF

y no es posible abrir dos conexiones distintas dentro de una sola transacción. El código de producción especificó un nombre de aplicación; por lo tanto funcionó; el código de prueba no. Especificando el argumento Application Name= corrigió el error para nosotros.

+0

Mi problema era aún más específico, una connectionstring usaba 'App = EntityFramework' y la otra usaba' Application Name = EntityFramework'. Lo mejor para hacer una prueba si este es su problema, es copiar las conexiones de un contexto y pasarlo como un parámetro cuando cree el segundo. –

Cuestiones relacionadas