Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Entity Framework 6 transaction rollback

With EF6 you have a new transaction which can be used like:

using (var context = new PostEntityContainer())         {             using (var dbcxtransaction = context.Database.BeginTransaction())             {                 try                 {                     PostInformation NewPost = new PostInformation()                     {                         PostId = 101,                         Content = "This is my first Post related to Entity Model",                         Title = "Transaction in EF 6 beta"                     };                     context.Post_Details.Add(NewPost);                     context.SaveChanges();                     PostAdditionalInformation PostInformation = new PostAdditionalInformation()                     {                         PostId = (101),                         PostName = "Working With Transaction in Entity Model 6 Beta Version"                     };                      context.PostAddtional_Details.Add(PostInformation);                     context.SaveChanges();                      dbcxtransaction.Commit();                 }                 catch                 {                     dbcxtransaction.Rollback();                 }             }         } 

Is rollback actually needed when things go sideways? I'm curious because the Commit description says: "Commits the underlying store transaction."

Whereas the Rollback description says: "Rolls back the underlying store transaction."

This makes me curious, because it looks to me that if Commit isn't called, the previously executed commands will not be stored (which seems logical to me). But if that is the case, what would the reason be to call the Rollback function? In EF5 I used TransactionScope which didn't have a Rollback function (only a Complete) which seemed logical to me. Due to MS DTC reasons I cannot use the TransactionScope anymore, but I also cannot use a try catch like the example above (i.e., I only need the Commit).

like image 499
The Cookies Dog Avatar asked Mar 18 '14 17:03

The Cookies Dog


People also ask

How do I rollback Entity Framework?

A DbContextTransaction object provides Commit() and Rollback() methods to do commit and rollback on the underlying store transaction. This method requires an open underlying stored connection. This method opens a connection if it is not already open. This method will close the connection when Dispose () is called.

Does TransactionScope work with Entity Framework?

Entity Framework is already operating within a TransactionScope. The connection object in the transaction passed is null. That is, the transaction is not associated with a connection – usually this is a sign that that transaction has already completed.

How do I use SaveChanges in Entity Framework?

The SaveChanges method of the DbContext prepares the Insert , Update & Delete Queries. It does so by tracking the changes to each of the entities' Context is tracking. Whenever we query the database for entities, the Context retrieves them and mark the entity as Unchanged .


2 Answers

You don't need to call Rollback manually because you are using the using statement.

DbContextTransaction.Dispose method will be called in the end of the using block. And it will automatically rollback the transaction if the transaction is not successfully committed (not called or encountered exceptions). Following is the source code of SqlInternalTransaction.Dispose method (DbContextTransaction.Dispose will finally delegate to it when using SqlServer provider):

private void Dispose(bool disposing) {     // ...     if (disposing && this._innerConnection != null)     {         this._disposing = true;         this.Rollback();     } } 

You see, it checks if _innerConnection is not null, if not, rollback the transaction (if committed, _innerConnection will be null). Let's see what Commit does:

internal void Commit()  {     // Ignore many details here...      this._innerConnection.ExecuteTransaction(...);      if (!this.IsZombied && !this._innerConnection.IsYukonOrNewer)     {         // Zombie() method will set _innerConnection to null         this.Zombie();     }     else     {         this.ZombieParent();     }      // Ignore many details here... }  internal void Zombie() {     this.ZombieParent();      SqlInternalConnection innerConnection = this._innerConnection;      // Set the _innerConnection to null     this._innerConnection = null;      if (innerConnection != null)     {         innerConnection.DisconnectTransaction(this);     } } 
like image 137
Mouhong Lin Avatar answered Oct 05 '22 03:10

Mouhong Lin


As long as you will always be using SQL Server with EF, there is no need to explicitly use the catch to call the Rollback method. Allowing the using block to automatically rollback on any exceptions will always work.

However, when you think about it from the Entity Framework point of view, you can see why all examples use the explicit call to Rollback the transaction. To the EF, the database provider is arbitrary and pluggable and the provider can be replaced with MySQL or any other database that has an EF provider implementation. Therefore, from the EF point of view, there is no guarantee that the provider will automatically rollback the disposed transaction, because the EF does not know about the implementation of the database provider.

So, as a best practice, the EF documentation recommends that you explicitly Rollback -- just in case you someday change providers to an implementation that does not auto-rollback on dispose.

In my opinion, any good and well written provider will automatically rollback the transaction in the dispose, so the additional effort to wrap everything inside the using block with a try-catch-rollback is overkill.

like image 34
Rwb Avatar answered Oct 05 '22 03:10

Rwb