Neb
Neb

Reputation: 354

EntityFramework, TransactionScope and SaveChange

I am working on a c# project with EntityFramework and the last developer wrote that:

using (System.Transactions.TransactionScope scope = new TransactionScope(TransactionScopeOption.Required, new TransactionOptions() { IsolationLevel = System.Transactions.IsolationLevel.ReadCommitted }))
{
    try
    {
        //... do somehting
        context.SaveChanges();

        //... do some other work
        context.SaveChanges();

        scope.Complete();
    }
    catch (Exception ex)
    {
       context.RollbackChanges();
       scope.Complete();
    }
}

I don't understand why he is using TransactionScope. I tried to throw an exception between the 2 SaveChanges and it didnt rollback the first call modification.

Why using TransactionScope?

Thanks

Upvotes: 4

Views: 5145

Answers (3)

Ashley Kurkowski
Ashley Kurkowski

Reputation: 206

This should explain it for you - https://blogs.msdn.microsoft.com/alexj/2009/01/11/savechangesfalse/

Edit: as per szer's request.

They key take-away from the link is :

"If you call SaveChanges() or SaveChanges(true),the EF simply assumes that if its work completes okay, everything is okay, so it will discard the changes it has been tracking, and wait for new changes."

Upvotes: 3

Leon Cullens
Leon Cullens

Reputation: 12476

Like Marc explained you need to roll back the TransactionScope, not the EF context transaction. TransactionScope creates an ambient transaction that operations can enlist in. So what you're doing here is creating a transaction that wraps multiple transactions and can commit or rollback all of them at once.

What's happening in your code is this:

  1. You're committing query 1 (with the SaveChanges call).
  2. You're committing query 2 (with the SaveChanges call).
  3. Error occurs.
  4. You're rolling back the latest transaction (query 2). Note that query 1 is still committed.
  5. You're committing the ambient transaction, 'saving' the results. This means that the final result is that query 1 was committed and query 2 was rolled back.

Upvotes: 3

Marc
Marc

Reputation: 3959

You need to call the Rollback() method on the scope object. To create the scope, call context.Database.BeginTransaction():

using (var scope = context.Database.BeginTransaction()) 
{ 
    try 
    { 
        // do some stuff 
        context.SaveChanges(); 

        // do other stuff 
        context.SaveChanges(); 

        scope.Commit(); 
    } 
    catch (Exception) 
    { 
        scope.Rollback(); 
    } 
} 

Upvotes: 3

Related Questions