2009-04-17 6 views
6

Possiedo un'applicazione Web che invia richieste a 3 database nel DAL. Sto scrivendo alcuni test di integrazione per assicurarmi che l'intero round trip delle funzionalità faccia effettivamente quello che mi aspetto che faccia. Questo è completamente separato dai miei test unitari, solo fyi.Come si ottengono più connessioni al database all'interno di TransactionScope se MSDTC è disabilitato?

Il modo in cui mi è stato l'intenzione di scrivere queste prove erano qualcosa per l'effetto di questa

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

Il presentatore, in questo caso è già stato impostato. Il problema entra in gioco all'interno del metodo ProcessWorkflow perché chiama vari repository che a loro volta accedono a diversi database e la mia casella sql server non ha MSDTC abilitato, quindi ricevo un errore ogni volta che provo a creare una nuova connessione sql, o provare per cambiare il database di una connessione memorizzata nella cache per sceglierne uno diverso.

Per brevità del presentatore assomiglia qualcosa come:

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

ho tentato molte cose per risolvere questo problema.

  1. Caching una connessione attiva a tutti i tempi e cambiare il database di destinazione
  2. Caching una connessione attiva per ogni database di destinazione (questa era una sorta di inutile perché il pool dovrebbe fare questo per me, ma ho voluto vedere se ottenuto risultati diversi)
  3. Aggiunta TransactionScopes aggiuntivi all'interno di ogni repository in modo che abbiano le proprie transazioni utilizzando il TransactionScopeOption "RequiresNew"

mio terzo tentativo sulla lista sembra qualcosa di simile:

E in realtà la terza cosa che ho provato in realtà ha fatto funzionare i test di unità, ma tutte le transazioni che hanno completato in realtà HIT il mio database! Quindi questo è stato un fallimento totale, dal momento che l'intero punto è di NON effettuare il mio database.

La mia domanda quindi è, quali altre opzioni sono là fuori per realizzare ciò che sto cercando di fare dati i vincoli che ho tracciato?

EDIT:

Questo è ciò che "// fare qualche lavoro di database" sarebbe simile

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

e il DataContext stesso sembra qualcosa di simile

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

Non sono sicuro di seguirlo. Cosa intendi per unità di lavoro? – Joseph

+0

Siamo spiacenti parlando di più server di database qui o più connessioni a un singolo server? – meandmycode

+0

più database sullo stesso server o più database su server diversi? Se si trovano sullo stesso server, non è necessario disporre di più database MSDTC – SQLMenace

risposta

1

Ok, ho trovato un modo per aggirare questo problema. L'unica ragione per cui lo sto facendo in questo modo è perché non riuscivo a trovare QUALSIASI altro modo per risolvere questo problema, e perché è nei miei test di integrazione, quindi non sono preoccupato di avere effetti negativi sul codice di produzione.

Ho dovuto aggiungere una proprietà al mio DataContext per fungere da flag per tenere traccia di se disporre o meno dell'oggetto di connessione quando il mio DataContext viene eliminato. In questo modo, la connessione viene tenuto in vita per tutto l'intero ambito di transazione, e dà fastidio quindi non più DTC

Ecco campione della mia nuova Smaltire:

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(); 
    } 
} 

questo permette i miei test di integrazione per prendere la forma di:

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

     Presenter.ProcessWorkflow(); 
    } 
} 

Non consiglierei di utilizzarlo nel codice di produzione, ma per i test di integrazione penso sia appropriato. Inoltre, tieni presente che funziona solo per le connessioni in cui il server è sempre lo stesso, così come l'utente.

Spero che questo aiuti chiunque altro che si imbatte nello stesso problema che ho avuto.

0

Se non voglio usare MSDTC puoi usare direttamente le transazioni SQL.

Vedere SqlConnection.BeginTransaction().

+0

Come funzionerebbe nel contesto di un test di integrazione? Se utilizzo BeginTransaction e Commit o Rollback a livello di repository, cosa succede quando avvolgo l'intera operazione attorno a un ambito di transazione? – Joseph