2009-07-28 18 views
17

Posso fare transazioni nidificate in NHibernate e come posso implementarle? Sto usando SQL Server 2008, quindi il supporto è sicuramente nel DBMS.Come faccio le transazioni nidificate in NHibernate?

trovo che se provo qualcosa di simile:

using (var outerTX = UnitOfWork.Current.BeginTransaction()) 
{ 
    using (var nestedTX = UnitOfWork.Current.BeginTransaction()) 
    { 
     ... do stuff 
     nestedTX.Commit(); 
    } 

    outerTX.Commit(); 
} 

quindi per il momento si tratta di outerTX.Commit() la transazione è diventato inattivo, e si traduce in un ObjectDisposedException sul AdoTransaction sessione.

Si suppone quindi di creare sessioni di NHibernate nidificate? O c'è qualche altra classe che dovremmo usare per avvolgere le transazioni (ho sentito parlare di TransactionScope, ma non sono sicuro di cosa sia)?

Ora sto usando Ayende's UnitOfWork implementation (grazie a Sneal).

Perdona ogni ingenuità in questa domanda, sono ancora nuovo di NHibernate.

Grazie!

EDIT: ho scoperto che è possibile utilizzare TransactionScope, come ad esempio:

using (var transactionScope = new TransactionScope()) 
{ 
    using (var tx = UnitOfWork.Current.BeginTransaction()) 
    { 
     ... do stuff 
     tx.Commit(); 
    } 

    using (var tx = UnitOfWork.Current.BeginTransaction()) 
    { 
     ... do stuff 
     tx.Commit(); 
    } 

    transactionScope.Commit(); 
} 

Tuttavia io non sono tutto ciò che entusiasti di questo, come ci blocca per l'utilizzo di SQL Server, e inoltre ho scoperto che se il database è remoto, devi preoccuparti di avere MSDTC abilitato ... un altro componente non funziona. Le transazioni nidificate sono così utili e facili da fare in SQL che presumo che NHibernate abbia un modo di emulare lo stesso ...

+1

Sei stato in grado di trovare la risposta? Come fare finalmente le transazioni nidificate? – learning

+0

@ user281180, una specie di. Non ho trovato alcun modo per realizzarli, ma puoi approssimare l'esperienza. Ho bloggato su di esso qui: http://blog.constructionhive.com/2010/07/22/nested-transactions-and-nhibernate/ – Gavin

risposta

1

Tale implementazione non supporta il nesting, se si desidera utilizzare il nesting Ayende's UnitOfWork implementation. Un altro problema con l'implementazione che state utilizzando (almeno per le app Web) è che trattiene l'istanza di ISession in una variabile statica.

Ho appena riscritto il nostro UnitOfWork ieri per questi motivi, originariamente basato su Gabriel.

Non usiamo UnitOfWork.Current.BeginTransaction(), usiamo UnitofWork.TransactionalFlush(), che crea una transazione separata alla fine per svuotare tutte le modifiche contemporaneamente.

using (var uow = UnitOfWork.Start()) 
{ 
    var entity = repository.Get(1); 
    entity.Name = "Sneal"; 
    uow.TransactionalFlush(); 
} 
+0

Sì, sento che avrei dovuto usare Rhino Commons fin dall'inizio ... Penso Sono andato con Gabriel's così ho potuto avere un'idea di come funzionava il pattern Unit Of Work costruendolo da zero (e mi ha aiutato molto a capire molto), ma forse ora è il momento di giocare con i grandi ragazzi ... grazie . – Gavin

+0

@Sneal: Abbiamo implementato UnitOfWork di Ayende utilizzando Rhino.Commons, ed è buono, ma non sono ancora chiaro su come far funzionare le transazioni nidificate.Il codice che ho descritto nella mia domanda originale agisce esattamente nello stesso modo di prima (ad esempio, gli oggetti della transazione sembrano essere condivisi). Puoi darmi qualche suggerimento? Grazie. – Gavin

2

Ho lottato con questo per un po 'di tempo. Avrò un'altra crepa.

Desidero implementare le transazioni in singoli contenitori di servizi, perché questo li rende autonomi, ma in seguito è possibile annidare molti di questi metodi di servizio all'interno di una transazione più grande e, se necessario, eseguire il rollback dell'intero lotto.

Perché sto usando Rhino Commons Ora ho intenzione di provare il refactoring utilizzando il metodo With.Transaction. Fondamentalmente ci permette di scrivere codice come se le transazioni fossero nidificate, anche se in realtà ce n'è solo una.

Ad esempio:

private Project CreateProject(string name) 
{ 
    var project = new Project(name); 
    With.Transaction(delegate 
    { 
     UnitOfWork.CurrentSession.Save(project); 
    }); 
    return project; 
} 

private Sample CreateSample(Project project, string code) 
{ 
    var sample = new Sample(project, code); 
    With.Transaction(delegate 
    { 
     UnitOfWork.CurrentSession.Save(sample); 
    }); 
    return sample; 
} 

private void Test_NoNestedTransaction() 
{ 
    var project = CreateProject("Project 1"); 
} 

private void TestNestedTransaction() 
{ 
    using (var tx = UnitOfWork.Current.BeginTransaction()) 
    { 
     try 
     { 
      var project = CreateProject("Project 6"); 
      var sample = CreateSample(project, "SAMPLE006", true); 
     } 
     catch 
     { 
      tx.Rollback(); 
      throw; 
     } 
     tx.Commit(); 
    } 
} 

In Test_NoNestedTransaction(), stiamo creando un progetto da solo, senza il contesto di una transazione più grande. In questo caso, in CreateSample verrà creata e impegnata una nuova transazione o verrà eseguito il rollback se si verifica un'eccezione.

Nel Test_NestedTransaction(), stiamo creando sia un campione che un progetto. Se qualcosa va storto, vogliamo che entrambi vengano ripristinati. In realtà, il codice in CreateSample e CreateProject verrà eseguito proprio come se non ci fossero transazioni; è interamente la transazione esterna che decide se eseguire il rollback o il commit e lo fa in base al fatto che venga lanciata un'eccezione. In realtà è per questo che sto usando una transazione creata manualmente per la transazione esterna; così io ho il controllo su se eseguire il commit o il rollback, piuttosto che il default su on-exception-rollback-else-commit.

si potrebbe ottenere la stessa cosa senza Rhino.Commons mettendo un sacco di questo genere di cose attraverso il vostro codice:

if (!UnitOfWork.Current.IsInActiveTransaction) 
{ 
    tx = UnitOfWork.Current.BeginTransaction(); 
} 

_auditRepository.SaveNew(auditEvent); 
if (tx != null) 
{ 
    tx.Commit(); 
} 

... e così via. Ma lo With.Transaction, nonostante il clunkiness di dover creare delegati anonimi, lo fa abbastanza convenientemente.

Un vantaggio di questo approccio rispetto all'utilizzo di TransactionScope s (a parte la dipendenza da MSDTC) è che ci dovrebbe essere solo un singolo svuotamento al database nel commit della transazione esterna finale, indipendentemente da quanti metodi sono stati chiamati nel mezzo. In altre parole, non abbiamo bisogno di scrivere dati non salvati nel database mentre andiamo, lo scriviamo sempre nella cache locale di NHibernate.

In breve, questa soluzione non offre il massimo controllo sulle transazioni, poiché non utilizza mai più di una transazione. Immagino di poterlo accettare, poiché le transazioni nidificate non sono affatto universalmente supportate in ogni DBMS. Ma ora forse posso almeno scrivere codice senza preoccuparmi se siamo già in una transazione o no.

13

Le sessioni di NHibernate non supportano le transazioni nidificate.

Il seguente test è sempre vero nella versione 2.1.2:

var session = sessionFactory.Open(); 
var tx1 = session.BeginTransaction(); 
var tx2 = session.BeginTransaction(); 
Assert.AreEqual(tx1, tx2); 

È necessario avvolgerla in un TransactionScope per supportare le transazioni nidificate.

MSDTC deve essere abilitato o si otterrà errore:

{"Network access for Distributed Transaction Manager (MSDTC) has been disabled. Please enable DTC for network access in the security configuration for MSDTC using the Component Services Administrative tool."}

+0

Questo significa, anche se creo transazioni nidificate in NHibernate, queste verranno considerate come una connessione più esterna? –

2

Come suggerito Satish, le transazioni nidificate non sono supportate in NHibernate. Non mi sono imbattuto in scenari in cui erano necessarie transazioni nidificate, ma certamente ho dovuto affrontare problemi in cui dovevo ignorare la creazione di transazioni se altre erano già attive in altre unità di lavoro.

Il blog link qui sotto fornisce un esempio di implementazione per NHibernate, ma dovrebbe funzionare anche per il server SQL: http://rajputyh.blogspot.com/2011/02/nested-transaction-handling-with.html

Problemi correlati