2017-03-24 1 views
2

Ich habe die Aussetzung der EF 6-Ausführungsstrategie überall dort implementiert, wo ich verteilte Transaktionen verwenden muss, um zu vermeiden, dass '' SqlAzureExecutionStrategy 'vom Benutzer initiierte Transaktionen nicht unterstützt' Ausnahmen nach diesen Beispielen:EF 6 Ausführungsstrategie und überlappende Ausführungen aussetzen - "Benutzerinitiierte Transaktionen werden nicht unterstützt" Ausnahme

https://romiller.com/2013/08/19/ef6-suspendable-execution-strategy/ https://msdn.microsoft.com/en-us/library/dn307226(v=vs.113).aspx

Doch vor kurzem habe ich zwei Fehler dieses während einer Sitzung Massendatenverwaltung, was nach allen oben genannten Ausnahme zu bekommen.

Wenn ich es richtig verstehe, aktivieren/deaktivieren die gegebenen Beispiele die Ausführungsstrategie auf globaler Ebene, was bedeutet, dass wenn Aktionen gleichzeitig an mehreren Threads ausgeführt werden, eine Aktion die Aufhebung beenden kann, bevor eine andere beendet wird. Der Effekt ist wahrscheinlich am auffälligsten, wenn .NET 4.6.1 für Transaktionen verwendet wird, die mehrere SQL Azure-DBs umfassen, was einige Zeit in Anspruch nehmen kann.

Um dies zu vermeiden, ich auf die Schaffung einer globalen Transaktionszähler zurückgegriffen, die in einem Thread sichere Art und Weise erhöht und erniedrigt, und Aufhebung der Aussetzung nur dann, wenn es mehr anhängig keine Transaktionen sind, wie:

public class MyConfiguration : DbConfiguration 
    { 
     public MyConfiguration() 
     { 
      this.SetExecutionStrategy("System.Data.SqlClient",() => SuspendExecutionStrategy 
       ? (IDbExecutionStrategy)new DefaultExecutionStrategy() 
       : new SqlAzureExecutionStrategy()); 
     } 

     public static bool SuspendExecutionStrategy 
     { 
      get 
      { 
       return (bool?)CallContext.LogicalGetData("SuspendExecutionStrategy") ?? false; 
      } 
      set 
      { 
       CallContext.LogicalSetData("SuspendExecutionStrategy", value); 
      } 
     } 
    } 

Und dann:

Ich bin immer noch verwirrt, dass das Beispiel auf MSDN berücksichtigt dies nicht berücksichtigt. Gibt es etwas, das ich übersehen habe?

Antwort

2

Update:

die Callcontext Stellt sich heraus, ist sowieso Thread spezifisch, so dass Sie sich auf jeden Fall in diesem Szenario keine Sorgen über Multi-Threading. (Siehe Bemerkungen: https://msdn.microsoft.com/en-us/library/system.runtime.remoting.messaging.callcontext(v=vs.110).aspx)


über das kam, während ich versuchte, etwas ähnlich zur Arbeit zu kommen.

Ziemlich sicher, dass Ihre Lösung nicht wirklich Thread sicher ist. Ein Thread kann immer noch kommen und die Aufhängung zwischen dem Zurücksetzen der Zahl und dem Setzen der Aufhängung auf "false" auf "true" setzen, was bedeutet, dass der neue Thread die Aufhängung nicht auf "true" gesetzt hätte und versagen würde.

Sie benötigen einen ReaderWriterLock, um sicherzustellen, dass Sie alle neuen Threads gesperrt haben, die die Suspendierung auf "True" setzen, während Sie die Suspendierung in der Reset-Methode dekrementiert, überprüft und "verfälscht" haben. Wie:

private ReaderWriterLock _readerWriterLock = new ReaderWriterLock(); 

    private void SuspendExeutionStrategy() 
    { 
     _readerWriterLock.AcquireReaderLock(_timeout); 
     Interlocked.Increment(ref _pendingTransactions); 
     MyConfiguration.SuspendExecutionStrategy = true; 
     _readerWriterLock.ReleaseReaderLock(); 
    } 


    private void ResetSuspension() 
    { 
     _readerWriterLock.AcquireWriterLock(_timeout); 
     Interlocked.Decrement(ref _pendingTransactions); 
     if (_pendingTransactions < 1) 
     { 
      MyConfiguration.SuspendExecutionStrategy = false; 
     } 
     _readerWriterLock.ReleaseWriterLock(); 
    } 
Verwandte Themen