Attualmente sto utilizzando TransactionScope per gestire le transazioni nel mio livello dati, ma ho riscontrato problemi con transazioni nidificate e asincrono in cui la connessione sembra essere chiusa durante la transazione nidificata o la transazione viene promossa a MSDTC. Non ho trovato il problema esatto, ma dopo aver letto in giro sembra che questo scenario non sia particuarly well supportato e che dovrei usare Database.BeginTransaction().Comportamento transazioni nidificate in EF6
Il mio problema è che non riesco a trovare informazioni su come Database.BeginTransaction() funziona con le transazioni nidificate, in particolare nel mio scenario in cui sto volendo utilizzare la transazione ambientale piuttosto che crearne una nuova. Il mio sospetto è che non è destinato a funzionare in questo modo e se voglio gestire le transazioni nidificate dovrei astrarre la gestione delle transazioni per darmi più controllo.
Non volendo aggiungere strati inutili di astrazioni, volevo sapere se qualcuno ha esperienza in quest'area e potrebbe confermare il comportamento di Database.BeginTransaction() quando è annidato in un'altra transazione?
Ulteriori informazioni sul mio DAL: Sulla base di modello CQS, tendo a incapsulare Db codice relativo al comando o di query gestori, quindi un esempio semplificato/artificiosa di come si verifica questo nidificazione sarebbe:
public class AddBlogPostHandler
{
private readonly MyDbContext _myDbContext;
public AddBlogPostHandler(MyDbContext myDbContext)
{
_myDbContext = myDbContext;
}
public async Task ExecuteAsync(AddBlogPostCommand command)
{
using (var scope = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled))
{
// .. code to create and add a draft blog post to the context
await _myDbContext.SaveChangesAsync();
var publishBlogPostCommand = new PublishBlogPostCommand();
// ..set some variables on the PublishBlogPostCommand
await PublishBlogPostAsync(command);
scope.Complete();
}
}
}
public class PublishBlogPostHandler
{
private readonly MyDbContext _myDbContext;
public PublishBlogPostHandler(MyDbContext myDbContext)
{
_myDbContext = myDbContext;
}
public async Task ExecuteAsync(PublishBlogPostCommand command)
{
using (var scope = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled))
{
// .. some code to do one set of update
await _myDbContext.SaveChangesAsync();
// .. some other db updates that need to be run separately
await _myDbContext.SaveChangesAsync();
scope.Complete();
}
}
}
Credo di chiedere davvero se una chiamata nidificata a "BeginTransaction" crea una nuova transazione (equivalente a "TransactionScopeOption.RequiresNew') o utilizza la transazione ambientale (Equivalente a" TransactionScopeOption.Required')? A parte la mia incapacità di farlo funzionare, il passaggio a 'BeginTransaction' era basato sulla sua raccomandazione per EF6 +. Sono aperto a provare a farlo funzionare con 'TransactionScope', ma se apro la connessione manualmente ottengo un'eccezione prima che la transazione esterna sia completata (transazione" completata ma non disposta ") –
BeginTransaction è come Richiesto. Non c'è modo di avere più trans sulla stessa connessione. Pertanto, non può possibilmente comportarsi come RequiresNew. "Essendo la loro raccomandazione per EF6" Ho letto anche questo, ma penso che non sia stato fornito alcun ragionamento. Strano consiglio 'Ricevo un'eccezione prima che la transazione esterna sia completata. Immagino che dovresti investigare e correggere il bug. Perché abbandonare l'intero approccio se tutto ciò che devi fare è correggere un bug minore? – usr
Ottimo, non sapevo che si potesse avere una sola transazione per connessione. Non potevo proprio "TransactionScope" lavorare nel mio scenario, così ho finito per scrivere una piccola astrazione, il che significava che avrei potuto avere scope di transazioni nidificate e comunque usare 'Database.BeginTransaction' per aprire alla transazione sottostante. Grazie per l'aiuto @ usr –