Using Transactions or AcceptAllChanges() and SaveChanges(false)?

c# entity-framework transactions

Question

Transactions seem to take care of themselves in EF as long as I pass, according to my investigation of them.false to SaveChanges() then make a callAcceptAllChanges() If no mistakes are present:

SaveChanges(false);
// ...
AcceptAllChanges();

Suppose anything goes wrong. Is the transaction terminated as soon as my procedure exits its scope, or do I need to rollback?

How are any identity columns that were assigned in the middle of the transaction handled? If someone else added a record after mine before mine went wrong, I assume that signifies an Identity value is lacking.

Is there a justification for using the standard?TransactionScope in my code a class?

1
342
3/20/2017 11:20:14 AM

Accepted Answer

the most of the time using the Entity FrameworkSaveChanges() is adequate. This starts a transaction or joins any ambient transaction and completes all the tasks inside it.

however sometimes theSaveChanges(false) + AcceptAllChanges() Pairing has a place.

The circumstances when you wish to do a distributed transaction over two separate Contexts are where this is most helpful.

For example, the following is bad:

using (TransactionScope scope = new TransactionScope())
{
    //Do something with context1
    //Do something with context2

    //Save and discard changes
    context1.SaveChanges();

    //Save and discard changes
    context2.SaveChanges();

    //if we get here things are looking good.
    scope.Complete();
}

If context1.SaveChanges() successful howevercontext2.SaveChanges() if a distributed transaction fails, it is terminated entirely. Sadly, though, the Entity Framework has already rejected the revisions.context1 therefore you can't effectively replay or report the failure.

But if you change your code to look like this:

using (TransactionScope scope = new TransactionScope())
{
    //Do something with context1
    //Do something with context2

    //Save Changes but don't discard yet
    context1.SaveChanges(false);

    //Save Changes but don't discard yet
    context2.SaveChanges(false);

    //if we get here things are looking good.
    scope.Complete();
    context1.AcceptAllChanges();
    context2.AcceptAllChanges();

}

even as the call toSaveChanges(false) transmits the required instructions to the database; the context is not altered, so you may repeat the process if necessary or query the database instead.ObjectStateManager if you'd like.

This indicates that if the transaction truly raises an exception, you may handle it by either retrying or reporting the current state of each context.ObjectStateManager somewhere.

To learn more, go to myblog entry.

447
2/21/2020 9:45:46 PM

Popular Answer

In terms of database calls to SQL, this has altered if you are using EF6 (Entity Framework 6+).
observe zzz-8 zzz

Be sure to use context.Database.BeginTransaction.

Using MSDN:

using (var context = new BloggingContext()) 
{ 
    using (var dbContextTransaction = context.Database.BeginTransaction()) 
    { 
        try 
        { 
            context.Database.ExecuteSqlCommand( 
                @"UPDATE Blogs SET Rating = 5" + 
                    " WHERE Name LIKE '%Entity Framework%'" 
                ); 

            var query = context.Posts.Where(p => p.Blog.Rating >= 5); 
            foreach (var post in query) 
            { 
                post.Title += "[Cool Blog]"; 
            } 

            context.SaveChanges(); 

            dbContextTransaction.Commit(); 
        } 
        catch (Exception) 
        { 
            dbContextTransaction.Rollback(); //Required according to MSDN article 
            throw; //Not in MSDN article, but recommended so the exception still bubbles up
        } 
    } 
} 


Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow