2014-10-31 11 views
5

jestem w stanie uzyskać następujący kod, który dotyka tylko jednej bazy danych przy użyciu jednego kontekstu do uruchomienia bez eskalacji do MSDTC i rzuca wyjątek na context.SaveChanges():Entity Framework zmuszając Distributed Transaction

public void DeleteGroupDetails(int groupId) 
{ 
    // Note there is no ambient tx 
    var thisIsNull = Transaction.Current; 

    using (var scope = new TransactionScope()) 
    { 
     var thisIsNotNull = Transaction.Current; 

     using (var context = new MyDbEntities()) 
     { 
      var deleted = context.tblGroups.Where(x => x.GroupID == groupId); 

      context.tblGroups.RemoveRange(deleted); 

      try 
      { 
       context.SaveChanges(); 
      } 
      catch (Exception e) 
      { 
       Console.WriteLine(e); 
      } 
     } 

     //scope.Complete(); 
    } 
} 

wyjątkiem jest „Podstawowym dostawcą powiodło się na Open -> menedżer transakcji partnerem wyłączył swoją obsługę transakcji zdalnych/sieciowych (wyjątek od HRESULT: 0x8004D025).”.

Uwaga:

  • To użyciu EF 6 i SQL Server 2005
  • W związku z zablokowanym serwerem db jestem w stanie korzystać MSDTC
  • Chcę używać TransactionScope w PKOl, ponieważ będzie to działa w WCF, który ma TransactionScope wybudowanym wi nie chcę zaśmiecać mojego kodu zarządzaniem transakcjami.
  • Podobne projekty użyciu NHibernate i nie mają tego problemu

String Connection jest:

connectionString = "metadane = res: // /ResourceAccess.MyDb.csdl|res:///ResourceAccess.MyDb.ssdl | res: //*/ResourceAccess.MyDb.msl; provider = System.Data.SqlClient; łańcuch połączenia dostawcy = " źródło danych = wil-gvpsqldev01; katalog początkowy = MyDb; integrated security = True; MultipleActiveResultSets = True: App = EntityFramework " "providerName =" System.Data.EntityClient "/>

System.Transactions diagnostyka są:

<E2ETraceEvent> 
    <System> 
     <EventID>0</EventID> 
     <Type>3</Type> 
     <SubType Name="Information">0</SubType> 
     <Level>8</Level> 
     <TimeCreated SystemTime="2014-10-31T14:39:43.0061489Z" /> 
     <Source Name="System.Transactions" /> 
     <Correlation ActivityID="{00000000-0000-0000-0000-000000000000}" /> 
     <Execution ProcessName="CCS.Host.Console.vshost" ProcessID="64568" ThreadID="13"/> 
     <Channel/> 
     <Computer>xxx</Computer> 
    </System> 
     <ApplicationData> 
      <TraceData> 
       <DataItem> 
        <TraceRecord Severity="Information"> 
         <TraceIdentifier>http://msdn.microsoft.com/2004/06/System/Transactions/TransactionCreate</TraceIdentifier> 
         <Description>Transaction Created</Description> 
         <AppDomain>CCS.Host.Console.vshost.exe</AppDomain> 
         <ExtendedData> 
          <TraceSource>[Lightweight]</TraceSource> 
          <TransactionTraceIdentifier> 
          <TransactionIdentifier>2e0814b3-7dd2-4c05-ad69-c3787d95c208:1</TransactionIdentifier> 
          <CloneIdentifier>1</CloneIdentifier> 
          </TransactionTraceIdentifier> 
         </ExtendedData> 
        </TraceRecord> 
       </DataItem> 
      </TraceData> 
     </ApplicationData> 
</E2ETraceEvent> 
<E2ETraceEvent> 
    <System> 
     <EventID>0</EventID> 
     <Type>3</Type> 
     <SubType Name="Information">0</SubType> 
     <Level>8</Level> 
     <TimeCreated SystemTime="2014-10-31T14:39:43.0181489Z" /> 
     <Source Name="System.Transactions" /> 
     <Correlation ActivityID="{00000000-0000-0000-0000-000000000000}" /> 
     <Execution ProcessName="CCS.Host.Console.vshost" ProcessID="64568" ThreadID="13"/> 
     <Channel/> 
     <Computer>xxx</Computer> 
    </System> 
    <ApplicationData> 
     <TraceData> 
      <DataItem> 
       <TraceRecord Severity="Information"> 
       <TraceIdentifier>http://msdn.microsoft.com/2004/06/System/Transactions/TransactionScopeCreated</TraceIdentifier> 
       <Description>TransactionScope Created</Description> 
       <AppDomain>CCS.Host.Console.vshost.exe</AppDomain> 
       <ExtendedData> 
        <TraceSource>[Base]</TraceSource> 
        <TransactionTraceIdentifier> 
        <TransactionIdentifier>2e0814b3-7dd2-4c05-ad69-c3787d95c208:1</TransactionIdentifier> 
        <CloneIdentifier>2</CloneIdentifier> 
        </TransactionTraceIdentifier> 
        <TransactionScopeResult>CreatedTransaction</TransactionScopeResult> 
       </ExtendedData> 
       </TraceRecord> 
      </DataItem> 
     </TraceData> 
    </ApplicationData> 
</E2ETraceEvent> 
<E2ETraceEvent> 
    <System> 
     <EventID>0</EventID> 
     <Type>3</Type> 
     <SubType Name="Information">0</SubType> 
     <Level>8</Level> 
     <TimeCreated SystemTime="2014-10-31T14:39:49.1921489Z"/> 
     <Source Name="System.Transactions"/> 
     <Correlation ActivityID="{00000000-0000-0000-0000-000000000000}"/> 
     <Execution ProcessName="CCS.Host.Console.vshost" ProcessID="64568" ThreadID="13"/> 
     <Channel/> 
     <Computer>ccc</Computer> 
    </System> 
    <ApplicationData> 
     <TraceData> 
      <DataItem> 
       <TraceRecord Severity="Information"> 
        <TraceIdentifier>http://msdn.microsoft.com/2004/06/System/Transactions/Enlistment</TraceIdentifier> 
        <Description>Enlistment Created</Description> 
        <AppDomain>CCS.Host.Console.vshost.exe</AppDomain> 
        <ExtendedData> 
         <TraceSource>[Lightweight]</TraceSource> 
         <EnlistmentTraceIdentifier> 
          <ResourceManagerId>00000000-0000-0000-0000-000000000000</ResourceManagerId> 
          <TransactionTraceIdentifier> 
           <TransactionIdentifier>2e0814b3-7dd2-4c05-ad69-c3787d95c208:1</TransactionIdentifier> 
           <CloneIdentifier>2</CloneIdentifier> 
          </TransactionTraceIdentifier> 
          <EnlistmentIdentifier>0</EnlistmentIdentifier> 
         </EnlistmentTraceIdentifier> 
         <EnlistmentType>PromotableSinglePhase</EnlistmentType> 
         <EnlistmentOptions>None</EnlistmentOptions> 
        </ExtendedData> 
       </TraceRecord> 
      </DataItem> 
     </TraceData> 
    </ApplicationData> 
</E2ETraceEvent> 
<E2ETraceEvent > 
    <System > 
     <EventID>0</EventID> 
     <Type>3</Type> 
     <SubType Name="Error">0</SubType> 
     <Level>2</Level> 
     <TimeCreated SystemTime="2014-10-31T14:39:50.8941489Z" /> 
     <Source Name="System.Transactions" /> 
     <Correlation ActivityID="{00000000-0000-0000-0000-000000000000}" /> 
     <Execution ProcessName="CCS.Host.Console.vshost" ProcessID="64568" ThreadID="13" /> 
     <Channel/> 
     <Computer>ccc</Computer> 
    </System> 
    <ApplicationData> 
     <TraceData> 
      <DataItem> 
       <TraceRecord Severity="Error"> 
        <TraceIdentifier>http://msdn.microsoft.com/2004/06/System/Transactions/TransactionException</TraceIdentifier> 
        <Description>TransactionException Thrown</Description> 
        <AppDomain>CCS.Host.Console.vshost.exe</AppDomain> 
        <ExtendedData xmlns="http://schemas.microsoft.com/2004/03/Transactions/TransactionExceptionTraceRecord"> 
         <TraceSource>[Distributed]</TraceSource> 
         <ExceptionMessage>The partner transaction manager has disabled its support for remote/network transactions. (Exception from HRESULT: 0x8004D025)</ExceptionMessage> 
        </ExtendedData> 
       </TraceRecord> 
      </DataItem> 
     </TraceData> 
    </ApplicationData> 
</E2ETraceEvent> 
<E2ETraceEvent > 
    <System > 
     <EventID>0</EventID> 
     <Type>3</Type> 
     <SubType Name="Warning">0</SubType> 
     <Level>4</Level> 
     <TimeCreated SystemTime="2014-10-31T14:39:50.9591489Z" /> 
     <Source Name="System.Transactions" /> 
     <Correlation ActivityID="{00000000-0000-0000-0000-000000000000}" /> 
     <Execution ProcessName="CCS.Host.Console.vshost" ProcessID="64568" ThreadID="13" /> 
     <Channel/> 
     <Computer>ccc</Computer> 
    </System> 
    <ApplicationData> 
     <TraceData> 
      <DataItem> 
       <TraceRecord xmlns="http://schemas.microsoft.com/2004/10/E2ETraceEvent/TraceRecord" Severity="Warning"> 
        <TraceIdentifier>http://msdn.microsoft.com/2004/06/System/Transactions/EnlistmentCallbackNegative</TraceIdentifier> 
        <Description>Enlistment Callback Negative</Description> 
        <AppDomain>CCS.Host.Console.vshost.exe</AppDomain> 
        <ExtendedData > 
         <TraceSource>[Lightweight]</TraceSource> 
         <EnlistmentTraceIdentifier> 
         <ResourceManagerId>00000000-0000-0000-0000-000000000000</ResourceManagerId> 
         <TransactionTraceIdentifier> 
          <TransactionIdentifier>2e0814b3-7dd2-4c05-ad69-c3787d95c208:1</TransactionIdentifier> 
          <CloneIdentifier>2</CloneIdentifier> 
         </TransactionTraceIdentifier> 
         <EnlistmentIdentifier>0</EnlistmentIdentifier> 
         </EnlistmentTraceIdentifier><EnlistmentCallback>Aborted</EnlistmentCallback> 
        </ExtendedData> 
       </TraceRecord> 
      </DataItem> 
     </TraceData> 
    </ApplicationData> 
</E2ETraceEvent> 
<E2ETraceEvent > 
    <System > 
     <EventID>0</EventID> 
     <Type>3</Type> 
     <SubType Name="Warning">0</SubType> 
     <Level>4</Level> 
     <TimeCreated SystemTime="2014-10-31T14:39:50.9601489Z" /> 
     <Source Name="System.Transactions" /> 
     <Correlation ActivityID="{00000000-0000-0000-0000-000000000000}" /> 
     <Execution ProcessName="CCS.Host.Console.vshost" ProcessID="64568" ThreadID="13" /> 
     <Channel/> 
     <Computer>ccc</Computer> 
    </System> 
    <ApplicationData> 
     <TraceData> 
      <DataItem> 
       <TraceRecord Severity="Warning"> 
        <TraceIdentifier>http://msdn.microsoft.com/2004/06/System/Transactions/TransactionAborted</TraceIdentifier> 
        <Description>Transaction Aborted</Description> 
        <AppDomain>CCS.Host.Console.vshost.exe</AppDomain> 
        <ExtendedData > 
         <TraceSource>[Lightweight]</TraceSource> 
         <TransactionTraceIdentifier> 
         <TransactionIdentifier>2e0814b3-7dd2-4c05-ad69-c3787d95c208:1</TransactionIdentifier> 
         </TransactionTraceIdentifier> 
        </ExtendedData> 
       </TraceRecord> 
      </DataIt 
+0

Czy są jakieś wyzwalacze na stole? –

+0

Wow, nawet o tym nie pomyślałem.Właśnie sprawdziłem i nie ma żadnych wyzwalaczy. –

Odpowiedz

3

Problem był z EF zamykania połączenia pomiędzy coraz podmioty na GroupID a następnie usuwając podmiotów. To powodowało eskalację. Prace wokół jest do sterowania otwieraniem i zamykaniem połączenia:

Dla EF6 i przyszłych wersjach Podjęliśmy podejście

http://msdn.microsoft.com/en-us/data/dn456849.aspx

Zachowanie w EF6 i przyszłe wersje jeśli powołania kod wybiera, aby otworzyć połączenie, wywołując context.Database.Connection.Open(), to ma dobry powód do robienia , więc framework zakłada, że ​​chce kontrolować otwarcie i zamknięcie połączenia i nie będzie już automatycznie zamknij połączenie .

Jedyna dokumentacja tego problemu udało mi się znaleźć to tabela w tym wpisie na blogu, który zakłada, że ​​wersje SQL Server przed rokiem 2008 będzie eskalować jeśli istnieje wiele połączeń:

https://petermeinl.wordpress.com/2011/03/13/avoiding-unwanted-escalation-to-distributed-transactions/

Tutaj gdzie wylądowałem:

using System; 
using System.Data; 

namespace Services.ResourceAccess 
{ 
    public class ResourceAccess : IDisposable 
    { 
     private readonly Lazy<MyDbEntities> _context; 

     public ResourceAccess() 
     { 
      _context = new Lazy<MyDbEntities>(() => 
      { 
       var context = new MyDbEntities(); 

       context.Database.Connection.Open(); 

       return context; 
      }); 
     } 

     public void DeleteGroupDetails(int groupId) 
     { 
      var deleted = _context.Value.tblGroupDetails.Where(x => x.GroupID == groupId); 

      _context.Value.tblGroupDetails.RemoveRange(deleted); 

      _context.Value.SaveChanges(); 
     } 

     public void Dispose() 
     { 
      if (_context.IsValueCreated) 
      { 
       if (_context.Value.Database.Connection.State == ConnectionState.Open) 
       { 
        _context.Value.Database.Connection.Close(); 
       } 
      } 
     } 
    } 
} 
+1

Nigdy nie widziałem takiego zachowania EF, aby MSDTC się uruchomiło. Powinno być całkiem możliwe otwieranie i zamykanie połączenia kontekstu wiele razy w ramach jednego 'TransactionScope'. Ale inne pytanie: dlaczego warto korzystać z TransactionScope, gdy jest tylko jedno wywołanie SaveChanges? –

+0

@GertArnold Dobre pytanie. Jeśli chodzi o TS, ten kod będzie ostatecznie żył w WCF, który używa TS, jeśli używasz wbudowanego zarządzania Tx. Kiedy już to zrobiłem, przeniosłem TS z tej metody do wywołującej metody i wywołałem inną metodę z innymi SaveChanges. Kiedy napotkam problem, staram się go maksymalnie uprościć, aby dostać się do głównej przyczyny, a powyższy kod był najprostszy, jaki mogłem uzyskać, póki jeszcze się nie udało. Zaktualizuję odpowiedź dotyczącą Twojego pierwszego pytania. –