in a case where there may be multiple DbContexts within a custom unit of work, would EF5 manage all the transactional requirements or is the code below still valid / required? If not, how far can the code be reduced and still provide the same functionality?
public void SaveAllChanges()
{
var transactions = new List<DbTransaction>();
foreach (var context in this.contexts
.Where(context => context != null)
.Select(dbcontext => ((IObjectContextAdapter)dbcontext).ObjectContext))
{
context.Connection.Open();
var databaseTransaction = context.Connection.BeginTransaction();
transactions.Add(databaseTransaction);
try
{
context.SaveChanges();
}
catch
{
foreach (var transaction in transactions)
{
try
{
transaction.Rollback();
}
finally
{
databaseTransaction.Dispose();
}
}
transactions.Clear();
throw;
}
}
try
{
foreach (var transaction in transactions)
{
transaction.Commit();
}
}
finally
{
foreach (var transaction in transactions)
{
transaction.Dispose();
}
transactions.Clear();
foreach (var context in this.contexts
.Select(dbcontext => ((IObjectContextAdapter)dbcontext).ObjectContext)
.Where(context => context.Connection.State != ConnectionState.Closed))
{
context.Connection.Close();
}
}
}
Assume SQL Server 2008 and above.
You must handle transactions yourselves when working with multiple contexts but your code is wrong. If any of your transactions fails during commit you can have part of transactions committed and part of transactions rolled back.
The only valid approach is to use
TransactionScopeand either manage connections for EF manually or live with distributed transactions:Here is described why AcceptAllChanges matters.