2009-04-17 6 views
6

Tengo una aplicación web que emite solicitudes a 3 bases de datos en el DAL. Estoy escribiendo algunas pruebas de integración para asegurarme de que la funcionalidad general de ida y vuelta hace realmente lo que espero que haga. Esto está completamente separado de mis pruebas unitarias, solo fyi.¿Cómo se manejan varias conexiones de bases de datos dentro de un TransactionScope si MSDTC está deshabilitado?

La forma en que tenía la intención de escribir estas pruebas eran algo en el sentido de esta

[Test] 
public void WorkflowExampleTest() 
{ 
    (using var transaction = new TransactionScope()) 
    { 
     Presenter.ProcessWorkflow(); 
    } 
} 

El presentador en este caso ya ha sido establecido. El problema entra en juego dentro del método ProcessWorkflow porque llama a varios Repositorios que a su vez acceden a diferentes bases de datos, y mi cuadro de servidor sql no tiene MSDTC habilitado, por lo que aparece un error cada vez que trato de crear una nueva conexión SQL o intento para cambiar la base de datos de una conexión en caché para que se oriente a una diferente.

Por brevedad el presentador se parece a algo como:

public void ProcessWorkflow() 
{ 
    LogRepository.LogSomethingInLogDatabase(); 
    var l_results = ProcessRepository.DoSomeWorkOnProcessDatabase(); 
    ResultsRepository.IssueResultstoResultsDatabase(l_results); 
} 

He intentado muchas cosas para resolver este problema.

  1. almacenamiento en caché de una conexión activa en todo momento y el cambio de la base de datos destino
  2. almacenamiento en caché de una conexión activa para cada base de datos destino (esto era algo inútil porque la puesta en común debe hacer esto por mí, pero yo quería ver si obtuvieron resultados diferentes)
  3. Adición TransactionScopes adicionales dentro de cada repositorio para que tengan sus propias transacciones utilizando el TransactionScopeOption "RequiresNew"

Mi tercera tentativa en la lista se ve algo como esto:

public void LogSomethingInLogDatabase() 
{ 
    using (var transaction = 
     new TransactionScope(TransactionScopeOption.RequiresNew)) 
    { 
     //do some database work 

     transaction.Complete(); 
    } 
} 

Y en realidad la tercera cosa que intenté en realidad fue que las pruebas unitarias funcionaran, ¡pero todas las transacciones que terminaron realmente HIT mi base de datos! Así que eso fue una falla total, ya que todo el punto es NO afectar mi base de datos.

Por lo tanto, mi pregunta es, ¿qué otras opciones hay para lograr lo que estoy tratando de hacer dadas las limitaciones que he expuesto?

EDIT:

Esto es lo que "// hacer un trabajo de base de datos" se vería como

using (var l_context = new DataContext(TargetDatabaseEnum.SomeDatabase)) 
{ 
    //use a SqlCommand here 
    //use a SqlDataAdapter inside the SqlCommand 
    //etc. 
} 

y el propio DataContext ve algo como esto

public class DataContext : IDisposable 
{ 
    static int References { get; set; } 
    static SqlConnection Connection { get; set; } 

    TargetDatabaseEnum OriginalDatabase { get; set; } 

    public DataContext(TargetDatabaseEnum database) 
    { 
     if (Connection == null) 
      Connection = new SqlConnection(); 

     if (Connection.Database != DatabaseInfo.GetDatabaseName(database)) 
     { 
      OriginalDatabase = 
       DatabaseInfo.GetDatabaseEnum(Connection.Database); 

      Connection.ChangeDatabase(
       DatabaseInfo.GetDatabaseName(database)); 
     }   

     if (Connection.State == ConnectionState.Closed) 
     { 
      Connection.Open() //<- ERROR HAPPENS HERE 
     }  

     ConnectionReferences++;     
    } 

    public void Dispose() 
    { 
     if (Connection.State == ConnectionState.Open) 
     { 
      Connection.ChangeDatabase(
       DatabaseInfo.GetDatabaseName(OriginalDatabase)); 
     } 

     if (Connection != null && --ConnectionReferences <= 0) 
     { 
      if (Connection.State == ConnectionState.Open) 
       Connection.Close(); 
      Connection.Dispose(); 
     } 
    } 
} 
+0

No estoy seguro de seguir. ¿Qué quiere decir unidad de trabajo? – Joseph

+0

Disculpa, ¿hablamos de servidores de bases de datos múltiples aquí o de conexiones múltiples a un solo servidor? – meandmycode

+0

bases de datos múltiples en el mismo servidor o bases de datos múltiples en servidores diferentes? Si están en los mismos servidores, entonces no necesita MSDTC – SQLMenace

Respuesta

1

Bien, encontré la manera de solucionar este problema. La única razón por la que lo hago de esta manera es porque no pude encontrar CUALQUIER otra forma de solucionar este problema, y ​​porque está en mis pruebas de integración, así que no me preocupa que esto tenga efectos adversos en el código de producción.

Tuve que agregar una propiedad a mi DataContext para que actuara como un indicador para hacer un seguimiento de si desechar o no el objeto de conexión cuando se está desechando mi DataContext. De esta manera, la conexión se mantiene viva en todo el ámbito de transacción, y por lo tanto ya no se molesta DTC

Aquí está la muestra de mi nuevo Desechar:

internal static bool SupressConnectionDispose { get; set; } 

public void Dispose() 
{ 
    if (Connection.State == ConnectionState.Open) 
    { 
     Connection.ChangeDatabase(
      DatabaseInfo.GetDatabaseName(OriginalDatabase)); 
    } 

    if (Connection != null 
     && --ConnectionReferences <= 0 
     && !SuppressConnectionDispose) 
    { 
     if (Connection.State == ConnectionState.Open) 
      Connection.Close(); 
     Connection.Dispose(); 
    } 
} 

esto permite que mis pruebas de integración que toman la forma de:

[Test] 
public void WorkflowExampleTest() 
{ 
    (using var transaction = new TransactionScope()) 
    { 
     DataContext.SuppressConnectionDispose = true; 

     Presenter.ProcessWorkflow(); 
    } 
} 

No recomendaría utilizar esto en el código de producción, pero para las pruebas de integración creo que es apropiado. También tenga en cuenta que esto solo funciona para las conexiones donde el servidor siempre es el mismo y el usuario.

Espero que esto ayude a cualquier otra persona que se encuentre con el mismo problema que tuve.

0

Si No quiero usar MSDTC, puede usar transacciones SQL directamente.

Ver SqlConnection.BeginTransaction().

+0

¿Cómo funcionaría esto en el contexto de una prueba de integración? Si utilizo BeginTransaction y Commit o Rollback en el nivel de Repository, ¿qué sucederá cuando ajuste todo alrededor de un alcance de transacción? – Joseph

Cuestiones relacionadas