2009-04-17 4 views
6

Ich habe eine Webanwendung, die Anforderungen an 3 Datenbanken in der DAL ausgibt. Ich schreibe einige Integrationstests, um sicherzustellen, dass der gesamte Funktionsumlauf tatsächlich das tut, was ich von ihm erwarte. Dies ist völlig getrennt von meinen Unit Tests, nur fyi. etwas auf die Wirkung dieser in diesem FallWie umgehen Sie mehrere Datenbankverbindungen in einem TransactionScope, wenn MSDTC deaktiviert ist?

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

Der Moderator

So wie ich waren diese Tests zu schreiben beabsichtigte, wurde bereits eingerichtet wurde. Das Problem tritt in der ProcessWorkflow-Methode auf, weil es verschiedene Repositories aufruft, die wiederum auf verschiedene Datenbanken zugreifen, und in meiner SQL Server-Box MSDTC nicht aktiviert ist, bekomme ich einen Fehler, wenn ich versuche, eine neue SQL-Verbindung zu erstellen oder zu versuchen die Datenbank einer zwischengespeicherten Verbindung ändern, um auf eine andere zuzugreifen.

Der Kürze halber ähnelt der Moderator etwas wie:

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

ich zahlreiche Dinge versucht haben, dieses Problem zu lösen.

  1. Caching eine aktive Verbindung zu allen Zeiten und die Änderung der Zieldatenbank
  2. Caching eine aktive Verbindung für jede Zieldatenbank (diese Art von nutzlos war, weil Pooling für mich, dies tun sollte, aber ich wollte, wenn ich sehen bekam unterschiedliche Ergebnisse)
  3. in jedem Repository zusätzliche TransactionScopes hinzufügen, damit sie ihre eigenen Transaktionen mit dem Transactionscope „RequiresNew“

Mein 3. Versuch auf der Liste etwas wie folgt aussieht:

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

     transaction.Complete(); 
    } 
} 

Und eigentlich die 3. Sache, die ich versuchte tatsächlich bekam die Unit-Tests zu arbeiten, aber alle Transaktionen, die tatsächlich abgeschlossen HIT meine Datenbank! Das war ein völliger Misserfolg, da der ganze Punkt darin besteht, meine Datenbank NICHT zu beeinflussen.

Meine Frage ist daher, welche anderen Möglichkeiten gibt es, um zu erreichen, was ich versuche, angesichts der Einschränkungen, die ich angelegt habe?

EDIT:

Dies ist, was "// einige Datenbank-Arbeit tun" wie

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

aussehen würde und die Datacontext selbst sieht so etwas wie dieses

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

Ich bin mir nicht sicher, ob ich folge. Was meinst du Arbeitseinheit? – Joseph

+0

Es tut uns leid, sprechen wir hier mehrere Datenbankserver oder mehrere Verbindungen zu einem einzelnen Server? – meandmycode

+0

mehrere Datenbanken auf demselben Server oder mehrere Datenbanken auf verschiedenen Servern? Wenn sie sich auf denselben Servern befinden, benötigen Sie MSDTC – SQLMenace

Antwort

1

Ok, ich habe einen Weg gefunden, dieses Problem zu umgehen. Der einzige Grund, warum ich es so mache, ist, dass ich keine andere Möglichkeit finden konnte, dieses Problem zu beheben, und weil es sich um meine Integrationstests handelt, bin ich nicht besorgt, dass dies negative Auswirkungen auf den Produktionscode haben könnte.

Ich musste eine Eigenschaft zu meinem DataContext hinzufügen, um als ein Flag zu fungieren, um zu verfolgen, ob das Verbindungsobjekt entsorgt werden soll oder nicht, wenn mein DataContext entsorgt wird. Auf diese Weise wird die Verbindung lebendig während des gesamten Transaktionsbereich gehalten, und daher nicht stört DTC mehr

Hier Probe meiner neuen entsorgen:

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

dies meine Integrationstests ermöglicht, die Form anzunehmen:

Ich würde nicht empfehlen, dies im Produktionscode zu verwenden, aber für Integrationstests denke ich, dass es angemessen ist. Beachten Sie auch, dass dies nur für Verbindungen funktioniert, bei denen der Server immer derselbe ist wie der Benutzer.

Ich hoffe, dass dies hilft jedem anderen, der in das gleiche Problem, das ich hatte, läuft.

0

Wenn Sie Möchten Sie MSDTC nicht verwenden, können Sie SQL-Transaktionen direkt verwenden.

Siehe SqlConnection.BeginTransaction().

+0

Wie würde das im Rahmen eines Integrationstests funktionieren? Wenn ich BeginTransaction und Commit oder Rollback auf der Repository-Ebene verwende, was passiert, wenn ich die gesamte Sache um einen Transaktionsbereich wickle? – Joseph