2009-02-12 12 views
69

¿Cuáles son las diferencias entre el patrón de transacciones clásico en LINQ a SQL como:TransactionScope vs Transacción en LINQ to SQL

using(var context = Domain.Instance.GetContext()) 
{ 
    try 
    { 
     context.Connection.Open(); 
     context.Transaction = context.Connection.BeginTransaction(); 
     /*code*/ 
     context.Transaction.Commit(); 
    } 
    catch 
    { 
     context.Transaction.Rollback(); 
    }   
} 

vs el objeto TransactionScope

using (var context = Domain.Instance.GetContext()) 
using (var scope = new TransactionScope()) 
{ 
    try 
    { 
     /*code*/ 
     scope.Complete(); 
    } 
    catch 
    { 
    } 
} 

Respuesta

34

Linq2SQL utilizará una transacción implícita. Si todas sus actualizaciones se realizan dentro de un solo envío, es posible que no necesite manejar la transacción usted mismo.

De la documentación (el énfasis es mío):

Cuando se llama a SubmitChanges, LINQ a SQL comprueba si la llamada se encuentra en el ámbito de una transacción o si la propiedad de transacción (IDbTransaction) se establece en una transacción local iniciada por el usuario. Si no encuentra ninguna transacción, LINQ to SQL inicia una transacción local (IDbTransaction) y la usa para ejecutar los comandos SQL generados. Cuando todos los comandos SQL se han completado con éxito, LINQ to SQL confirma la transacción local y regresa.

+10

Si necesita enviar algo con propiedades cíclicas (común), acierta un error en LINQ to SQL que requiere que elimine una parte de cada referencia bidireccional, envíe, repare las referencias bidireccionales y envíe nuevamente. Debe envolver todo esto en su propia transacción para hacerlo. Es una necesidad común, por lo que "No te preocupes" no es la mejor respuesta. –

4

creo que son fundamentalmente los mismos que la clase TransactionScope se conectará con la conexión subyacente de ADO.NET para crear y confirmar o revertir la transacción. Que la clase TransactionScope acaba de crearse para que el trabajo con ADO.NET sea más limpio.

Editar: Aclarando mi declaración con respecto a casperOne's addition es el TransactionScope que va a crear la transacción y la conexión verá entonces la transacción que fue creado por el TransactionScope y utilizarlo ya que es a su disposición.

+0

@Christ Marisic: Es al revés. La conexión busca la presencia de una Transacción para el hilo actual, que sería creado por TransactionScope. Si hay uno, entonces se alista con la Transacción. El coordinador luego le dirá a la conexión que confirme o restituya. – casperOne

69

Debe tenerse en cuenta que al utilizar el TransactionScope no hay necesidad de que el try/catch constructo que tiene. Simplemente debe llamar al Complete en el alcance para comprometer la transacción cuando se sale del alcance.

Dicho esto, TransactionScope suele ser una mejor opción porque le permite anular llamadas a otros métodos que pueden requerir una transacción sin tener que pasar el estado de la transacción.

Al llamar al BeginTransaction en el objeto DbConnection, debe pasar ese objeto transaccional si desea realizar otras operaciones en la misma transacción, pero con un método diferente.

Con TransactionScope, mientras el alcance exista, manejará todo lo que se registre con el Transaction actual en la secuencia, haciendo que su código sea más limpio y más fácil de mantener.

Además de eso, tiene la ventaja adicional de poder utilizar otros recursos que pueden participar en transacciones, no solo la conexión a la base de datos.

Debe tenerse en cuenta que en situaciones en las que necesita aprovechar al máximo sus conexiones y operaciones de base de datos, es posible que no desee utilizar TransactionScope; incluso contra una única base de datos, se ejecuta la posibilidad de que se utilice el Coordinador de transacciones distribuidas y que la transacción se convierta en una transacción distribuida (incluso para una única conexión de base de datos).

En estos casos, mientras enturbia su diseño, es posible que desee considerar pasar una transacción específica de conexión.

O, si sabe que usará un recurso consistentemente (y en el mismo subproceso), es posible que desee crear una clase que cuente como referencia su conexión/transacción.

Debería crear una clase que durante la construcción, cree su recurso/incremente el recuento. También implementaría IDisposable (en el que disminuiría/liberar/confirmar/abortar cuando el recuento es cero), y almacenar el recuento en una variable que tiene ThreadStaticAttribute aplicado.

Esto le permite separar la gestión de transacciones del código lógico, y aún aferrarse a un recurso singular con bastante eficiencia (en lugar de escalar a una transacción distribuida).

+0

si utilizo una única conexión con transacción, entonces ¿no es lo mismo? Quiero decir, evitas las transacciones distribuidas. – GorillaApe

+0

@Parhs Depende de si tienes o no otros recursos transaccionales enlistados en la transacción con la conexión de la base de datos única. – casperOne

+0

mi proveedor no permite transacciones anidadas (base de datos), entonces ¿hay algún problema? – GorillaApe

19

Una gran diferencia (lección aprendida por las malas): TransactionScope usa MS DTC para la gestión de transacciones.

Si su aplicación tiene que gestionar la transacción de la base de datos solamente, y no hay servicios o llamadas remotas, puede omitir los posibles problemas relacionados con MS DTC mediante el uso de transacciones nativas a las bases de datos (DbTransactions).

+0

también aprendí esto de la manera difícil! Pero me alegro de haber resuelto una pesadilla con msdtc – DevDave

+0

Mayank (o cualquier otra persona). Me encontré con más problemas con Transaction y UnitTesting, ¿podría ayudarme con este http://stackoverflow.com/questions/9636533/mvc3-differences-between-test-environment-and-dev-application en absoluto? – DevDave

+5

Esto no es verdad todo el tiempo.'TransactionScope' escalará desde una transacción del kernel hasta una transacción DTC dependiendo de la necesidad. Sin embargo, todo esto está oculto para ti. El punto importante es que no * siempre * hace esto, sino * según sea necesario *. – casperOne

4

TransactionScope proporciona administración unificada para todos los administradores de recursos (servidor SQL, directorio activo, sistema de archivos, ...). Además, uno puede escribir su propio administrador de recursos: código que detecta el alcance de la transacción, se une a él y funciona exactamente como lo hace el servidor SQL: confirma o revierte los cambios como otros participantes de la transacción. Creía que TransactionScope es dominante y olvidé las transacciones nativas de MS SQL hasta que falló en una gran trampa: Windows Server 2008 Edición WEB viene con un servicio de Coordinador de transacciones distribuidas restringido y el alcance de transacción funciona solo en una sola computadora. Su aplicación ASP.NET fallará en este sistema si IIS y el servidor SQL están instalados en computadoras diferentes. Tenga en cuenta que la mayoría de los proveedores de dominio público suministran la edición WEB de Windows Server y el servidor SQL se encuentran en servidores separados. Esto significa que debe trabajar con transacciones nativas usando la administración de transacciones explícita ...