2013-07-18 5 views
5

Ich verwende EF5.0 mit SQL Server 2008. Ich habe zwei Datenbanken auf der gleichen Serverinstanz. Ich muss Tabellen in beiden Datenbanken aktualisieren und möchte, dass sie dieselbe Transaktion sind. Also habe ich das TransactionScope benutzt. Unten ist der Code -Mehrere Datenbanken (Datenkontext) auf demselben Server ohne MS DTC

public void Save() 
{ 
     var MSObjectContext = ((IObjectContextAdapter)MSDataContext).ObjectContext; 
     var AWObjectContext = ((IObjectContextAdapter)AwContext).ObjectContext; 

     using (var scope = new TransactionScope(TransactionScopeOption.Required, 
              new TransactionOptions 
               { 
                IsolationLevel = IsolationLevel.ReadUncommitted 
               })) 
     {    
      MSObjectContext.SaveChanges(SaveOptions.DetectChangesBeforeSave); 
      AWObjectContext.SaveChanges(SaveOptions.DetectChangesBeforeSave); 

      scope.Complete(); 
     } 
    } 

Wenn ich den obigen Code verwende, wird die Transaktion zum DTC befördert. Nach der Suche im Internet habe ich festgestellt, dass dies aufgrund zweier verschiedener Verbindungen/Verbindungen geschieht. Aber was ich nicht verstehe, ist, wenn ich eine gespeicherte Prozedur auf eine Datenbank schreibe, die die Tabelle in einer anderen Datenbank (auf demselben Server) aktualisiert, ist kein DTC erforderlich. Warum fördert EF oder TransactionScope dies für DTC? Gibt es dafür noch andere Arbeiten?

Bitte geben

Vielen Dank im Voraus

Sai

Antwort

4

Mit Ebene DbConnection s, können Sie DTC Eskalation für mehrere Datenbanken auf dem gleichen Server verhindern, indem die gleiche Verbindungszeichenfolge (mit einem beliebigen Datenbank mit Ihnen wie) und ändern Sie die Datenbank auf dem geöffneten Verbindungsobjekt wie folgt manuell:

Dies wird nicht zu DTC eskalieren, aber es würde, wenn Sie andere Werte für connectStr verwenden.

Ich bin nicht vertraut mit EF und wie es Verbindungen und Kontexte verwaltet, aber mit den obigen Erkenntnissen können Sie möglicherweise DTC Eskalation vermeiden, indem Sie eine conn.ChangeDatabase(..) machen und dann Ihren Kontext wie new DbContext(conn, ...) erstellen.

Aber bitte beachten Sie, dass auch bei einer gemeinsamen Verbindungszeichenfolge, sobald Sie zur gleichen Zeit geöffnet zwei Anschlüsse haben, wird der DTC einlassen, wie in diesem modifizierten Beispiel:

using (var tx = new TransactionScope()) 
{ 
    using (var conn = new SqlConnection(mssqldb)) 
    { 
     conn.Open(); 
     new SqlCommand("INSERT INTO atest VALUES (1)", conn).ExecuteNonQuery(); 
     using (var conn2 = new SqlConnection(mssqldb)) 
     { 
      conn2.Open(); 
      conn2.ChangeDatabase("otherdatabase"); 
      new SqlCommand("INSERT INTO btest VALUES (2)", conn2).ExecuteNonQuery(); 
     } 
    } 
    tx.Complete(); 
} 
+0

Ich mag begehen Transaktionen auf zwei völlig verschiedenen dbs auf demselben Server unter einem Transaktionsumfang. Ich könnte das durch gespeicherte Prozeduren tun, aber nicht durch EF. Danke für deine Antwort. – Sai

+0

Meine Antwort zeigt, wie man ein 'TransactionScope' verwendet, ohne auf gespeicherte Prozeduren zurückzugreifen. Die implizite 'tx.Dispose()', die nach der Zeile 'tx.Complete() 'auftritt, wird die einzelne Transaktion festschreiben, die beide INSERTs zu zwei verschiedenen Datenbanken umfasst. Wie bereits erwähnt, gibt es bei EF Möglichkeiten, Verbindungen bereitzustellen, bei denen Sie 'ChangeDatabase()' manuell aufgerufen haben, aber abhängig von Ihrer Codebasis, die zu eng gekoppeltem Code führen können (während der Punkt 'TransactionScoep' Code entkoppeln soll), nur du kannst es sagen. –

+0

Ich glaube nicht, dass ich ChangeDatabase() verwenden könnte, da ich Databasefirst Ansatz verwende und mein dbcontext fest an die Entitäten gebunden ist. Wenn ich die Verbindungszeichenfolge zur Laufzeit in eine völlig andere Datenbank ändere, wird ein Fehler ausgegeben. – Sai

Verwandte Themen