2009-04-27 16 views
24

Vedere il codice qui sotto. Se inizializzo più di un contesto di entità, ottengo la seguente eccezione sul numero di codice solo. Se commento il secondo set funziona.Perché TransactionScope non funziona con Entity Framework?

{ "Il provider sottostante fallito su Open."}

interno: { "La comunicazione con il gestore delle transazioni sottostante ha fallito."}

interno: { "Errore HRESULT_E_FAIL è stato restituito da una chiamata a un componente COM. "}

Si noti che questa è un'app di esempio e so che non ha senso creare 2 contesti di seguito. Tuttavia, il codice di produzione ha motivo di creare più contesti nello stesso TransactionScope e questo non può essere modificato.

Modifica

Ecco una domanda precedente di me cercando di installare MS-DTC. Sembra essere abilitato sia sul server che sul client. Non sono sicuro se è impostato correttamente. Si noti inoltre che uno dei motivi per cui sto cercando di farlo è che il codice esistente all'interno di TransactionScope utilizza ADO.NET e Linq 2 Sql ... Vorrei che anche quelli usassero la stessa transazione. (Probabilmente è pazzesco, ma ho bisogno di farlo funzionare se possibile).

How do I use TransactionScope in C#?

Soluzione

Windows Firewall stava bloccando le connessioni a MS-DTC.

using(TransactionScope ts = new System.Transactions.TransactionScope()) 
     { 
       using (DatabaseEntityModel o = new DatabaseEntityModel()) 
       { 
        var v = (from s in o.Advertiser select s).First(); 
        v.AcceptableLength = 1; 
        o.SaveChanges(); 
       } 

       //-> By commenting out this section, it works 
       using (DatabaseEntityModel o = new DatabaseEntityModel()) 
       { 
        //Exception on this next line 
        var v = (from s1 in o.Advertiser select s1).First();       v.AcceptableLength = 1; 
        o.SaveChanges(); 
       } 
       //-> 

       ts.Complete(); 
     } 

risposta

18

MS-DTC (Distributed Transaction coordinatore) non funziona correttamente per qualche motivo. MS-DTC viene utilizzato per coordinare i risultati delle transazioni su più risorse eterogenee, incluse più connessioni sql.

Dai un'occhiata a this link per ulteriori informazioni su ciò che sta accadendo.

Fondamentalmente se ci si assicura che il proprio MS-DTC sia in esecuzione e funzioni correttamente, non si dovrebbero avere problemi con l'utilizzo di 2 connessioni ADO.NET, indipendentemente dal fatto che si tratti di connessioni di strutture entità o di qualsiasi altro tipo.

+4

Questo funziona ora. Windows Firewall stava bloccando le connessioni a MS-DTC. – NotDan

19

È possibile evitare di utilizzare una transazione distribuita per gestire il proprio EntityConnection e passando questo EntityConnection al vostro ObjectContext. Altrimenti, controlla questi.

http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=580828&SiteID=1&mode=1 http://forums.microsoft.com/msdn/showpost.aspx?postid=113669&siteid=1&sb=0&d=1&at=7&ft=11&tf=0&pageid=1

EntityConnection conn = new EntityConnection(ConnectionString); 

using (TransactionScope ts = new TransactionScope()) 
{ 
    using (DatabaseEntityModel o = new DatabaseEntityModel(conn)) 
    { 
      var v = (from s in o.Advertiser select s).First(); 
      v.AcceptableLength = 1; 
    } 

    //-> By commenting out this section, it works 
    using (DatabaseEntityModel o = new DatabaseEntityModel(conn)) 
    { 
     //Exception on this next line 
     var v = (from s1 in o.Advertiser select s1).First(); 
       v.AcceptableLength = 1; 
    } 
    //-> 

    ts.Complete(); 
} 
+0

Non sto solo utilizzando Entity Framework, quindi riutilizzare EntityConnection non è una soluzione facile neanche (vedi modifica sopra) – NotDan

+6

+1 per evitare DTC. Non che sia male, è solo che le transazioni distribuite non sono qualcosa da scegliere alla leggera. È uno stretto legame tra applicazione e risorse, che rischia di scarseggiare per design. –

+0

È inoltre possibile chiamare context.Connection.Open() per gestirlo manualmente. Non è necessario creare EntityConnection manualmente –

1

Il problema è che 2 DataContext diverso creare efficacemente due connessioni differenti.

In tal caso, la transazione deve essere promossa a una transazione distribuita. Presumo che il problema derivi dalla configurazione di MS DTC (Microsoft Distributed Transaction Coordinator) sul server o sul client. Se il server non è configurato per consentire le connessioni remote per MSDTC, ad esempio, si verificherà questo tipo di eccezione.

è possibile fare riferimento a this MS page ad esempio per la risoluzione dei problemi MSDTC e Google è pieno fino all'orlo di domande su forum/articoli su di esso.

Ora, potrebbe essere qualcosa di diverso, ma suona davvero come si tratta di un problema di MSDTC.

+0

Vedere la mia modifica sopra. Penso che tu abbia ragione e sto cercando di ottenere l'installazione di MS-DTC ... Non sono sicuro del perché non funzioni. – NotDan

0

Ho scritto una risposta in un'altra domanda su come diagnosticare il fallimento delle transazioni MSDTC.

La risposta potrebbe essere utile.

How do I enable MSDTC on SQL Server?

3

BTW si dovrebbe considerare l'utilizzo di SaveChanges (false) in combinazione con AcceptChanges() quando si utilizza le transazioni esplicite come questo.

In questo modo se qualcosa non riesce a SaveChanges (falsi), l'ObjectContext non ha annullato i cambiamenti in modo da poter applicare nuovamente tardive e fare qualche errore di registrazione ecc

Vedi questo post per maggiori informazioni: http://blogs.msdn.com/alexj/archive/2009/01/11/savechanges-false.aspx

Acclamazioni

Alex

5

Aggiungi C: \ Windows \ msdtc.exe alle eccezioni del firewall sia sul firewall e server. Ho passato anni a monkeying intorno all'apertura di numeri di porta e gamme specifici senza alcun risultato prima di farlo.

0

Ho avuto errori simili durante l'utilizzo di DTC durante la lettura dei messaggi dalla coda MQ, l'elaborazione e l'archiviazione nel database SQL 2005 Express Edition. Non ho abbastanza tempo per indagare fino alla fine se l'edizione 2005 o excatly Express ha causato questo problema, ma il passaggio allo standard 2008 ha sbiadito quel particolare comportamento.

4

Qui rimarrò qui perché ho passato 3 ore con un collega che ha eseguito il debugging di questo problema. Ogni singola risposta che circonda questo dice che questo è sempre un problema di firewall; tuttavia nel nostro caso non lo era. Spero che questo possa risparmiare a qualcun altro il dolore.

La situazione che abbiamo è che siamo attualmente in fase di migrazione verso Entity Framework. Ciò significa che abbiamo parti del codice all'interno delle quali sono aperte le connessioni di una singola transazione sia direttamente utilizzando uno new SqlConnection(connectionString).Open() sia indirettamente utilizzando un contesto di dati EF.

Questo ha funzionato bene nella nostra applicazione per un po ', ma quando abbiamo iniziato a fare retrospettivamente test sul codice che ha funzionato in produzione, il codice eseguito dal runner di test ha continuato a lanciare questo errore la prima volta che l'EF oggetto ha provato a connettersi al database dopo una connessione diretta era stata effettuata nella stessa transazione.

La causa del bug alla fine si è rivelato essere che se non si fornisce un argomento Application Name= per la stringa di connessione, Entity Framework aggiunge uno per impostazione predefinita (qualcosa come EntityFrameworkMUF).Ciò significa che si hanno due connessioni distinte nel proprio pool di connessioni:

  1. quella che si apre manualmente senza Application Name= argomento
  2. Un generato automaticamente un suffisso Application Name=EntityFrameworkMUF

e non è possibile aprire due connessioni distinte all'interno di una singola transazione. Il codice di produzione ha specificato un nome di applicazione; quindi ha funzionato; il codice di test no. La specifica dell'argomento Application Name= ha corretto il bug per noi.

+0

Il mio problema era ancora più specifico, una connessione stava usando 'App = EntityFramework' mentre l'altra stava usando' Nome applicazione = EntityFramework'. La cosa migliore da testare se questo è il tuo problema, è copiare il connectiontring da un contesto e passarlo come parametro quando crei il secondo. –

Problemi correlati