2014-10-31 22 views
5

non sono in grado di ottenere il seguente codice che tocca solo un singolo database utilizzando un unico contesto di correre senza escalation di MSDTC, e sta gettando un'eccezione context.SaveChanges():Entity Framework forzatura 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(); 
    } 
} 

L'eccezione è "Il provider sottostante non è riuscita su Open -> Il gestore delle transazioni partner ha disabilitato il proprio supporto per le transazioni remote/di rete (eccezione da HRESULT: 0x8004D025).".

Nota:

  • Questo è utilizzando EF 6 e SQL Server 2005
  • causa di un server db bloccato non sono in grado di utilizzare MSDTC
  • voglio utilizzare TransactionScope nel POC, perché questo sarà in esecuzione in WCF, che ha TransactionScope costruito in e non voglio sporcare il mio codice con la gestione delle transazioni.
  • Progetti simili usare NHibernate e non hanno questo problema

stringa di connessione è:

ConnectionString = "metadati = res: // /ResourceAccess.MyDb.csdl|res:///ResourceAccess.MyDb.ssdl | res: //*/ResourceAccess.MyDb.msl; provider = System.Data.SqlClient; provider connection string = " origine dati = wil-gvpsqldev01; catalogo iniziale = MyDb; sicurezza integrata = True; MultipleActiveResultSets = Vero; App = EntityFramework " "providerName =" System.Data.EntityClient "/>

System.Transactions diagnostica sono:

<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

Ci sono dei trigger sul tavolo, forse? –

+0

Wow, non ci ho nemmeno pensato.Appena controllato e non ci sono trigger. –

risposta

3

Il problema era con EF di chiudere la connessione tra ottenere enti per groupId e quindi eliminare le entità. Questo stava causando l'escalation. Il lavoro intorno è quello di controllare l'apertura e la chiusura della connessione:

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

Comportamento in EF6 e le versioni future

Per EF6 e le versioni future abbiamo preso l'approccio che se il chiamata il codice sceglie di aprire la connessione chiamando context.Database.Connection.Open() quindi ha una buona ragione per fare così e il framework assumerà che vuole il controllo sull'apertura e la chiusura della connessione e non sarà più chiudere automaticamente la connessione .

L'unica documentazione di questo comportamento sono riuscito a trovare è il tavolo in questo blog che implica che le versioni di SQL Server precedenti al 2008 aumenteranno se ci sono più connessioni:

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

Qui è dove sono atterrato:

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

Non ho mai visto questo comportamento di EF causa l'ingresso di MSDTC. Dovrebbe essere perfettamente possibile aprire e chiudere la connessione del contesto più volte all'interno di un 'TransactionScope'. Ma un'altra domanda: perché usare TransactionScope quando c'è una sola chiamata SaveChanges? –

+0

@GertArnold Buona domanda. Per quanto riguarda TS questo codice alla fine vivrà in WCF che usa TS se si utilizza la gestione Tx integrata. Una volta ottenuto questo lavoro ho spostato il TS fuori da questo metodo in un metodo di chiamata e ho chiamato un altro metodo con un altro SaveChanges. Quando mi imbatto in un problema, cerco di semplificarlo il più possibile per arrivare alla causa principale e il codice sopra riportato è il più semplice che potessi capirlo mentre ancora fallisco. Aggiornerò la risposta riguardante la tua prima domanda. –