Xceedas

Xceedas
xceedas

Tuesday, 16 September 2014

Working With Transaction in Entity Framework 6.0

Introduction
Entity Framework internally maintains transactions when the SaveChanges() method is called. It means the Entity Framework maintains a transaction for the multiple entity insert, update and delete in a single SaveChanges() method. When we execute another operation, the Entity Framework creates a new transaction.

For example I have two entities, employee and department, and I have added the employee and department entities to the context object and finally call the SaveChanges() method. The Entity Framework creates a single transaction for these multiple inserts.
  1. using (EntitiesContext context = new EntitiesContext())  
  2. {  
  3.     EmployeeMaster employee = new EmployeeMaster();  
  4.     employee.Code = "A0001";  
  5.     employee.Name = "Jignesh Trivedi";  
  6.     employee.DepartmentId = 1;  
  7.     context.Employees.Add(employee);  
  8.   
  9.     DepartmentMaster dept = new DepartmentMaster();  
  10.     dept.Code = "DEP0001";  
  11.     dept.Name = "Department 1";  
  12.     context.Departments.Add(dept);  
  13.   
  14.     context.SaveChanges();  
  15.     Console.ReadLine();  
  16. }  
SQL logging output:

program output

query output

Earlier the System.Transactions namespace was used to handle transactions in the Entity Framework using TransactionScope and the Entity Framework uses this transaction to save the changes in the database.
  1. using (TransactionScope scope = new TransactionScope())  
  2. {  
  3.       //Code Here  
  4. }  
New API with Entity Framework 6.0
Entity Framework 6.0 introduced two new APIs to maintain the transaction. 
  1. DbContext.Database.BeginTransaction: It allows us to begin a transaction. It allows us to combine several operations to be combined within the same transaction and hence all the transactions are either committed or rolled back. This method allows us to specify the isolation level for the transaction.
  2. DbContext.Database.UseTransaction: It allows DbContext to use a transaction that was stated outside of the Entity Framework. It means using this API we can use any existing transaction with Entity Framework.
DbContext.Database.BeginTransaction
This method returns a DbContextTransaction object. The BeginTransaction method has two overloads, one has no argument and the other accepts an explicit Isolation Level. 

A DbContextTransaction object provides Commit() and Rollback() methods to do commit and rollback on the underlying store transaction.

Test Code
  1. using (EntitiesContext context = new EntitiesContext())  
  2. {  
  3.     using (var transaction = context.Database.BeginTransaction())  
  4.     {  
  5.         try  
  6.         {  
  7.             EmployeeMaster employee = new EmployeeMaster();  
  8.             employee.Code = "A0001";  
  9.             employee.Name = "Jignesh Trivedi";  
  10.             employee.DepartmentId = 1;  
  11.             context.Employees.Add(employee);  
  12.             context.SaveChanges();  
  13.   
  14.             DepartmentMaster dept = new DepartmentMaster();  
  15.             dept.Code = "DEP0001";  
  16.             dept.Name = "Department 1";  
  17.             context.Departments.Add(dept);  
  18.             context.SaveChanges();  
  19.   
  20.             transaction.Commit();  
  21.         }  
  22.         catch (Exception ex)  
  23.         {  
  24.             transaction.Rollback();  
  25.         }  
  26.     }  
  27. }  
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.

The overloaded version of the DbContext.Database.BeginTransaction method:

DbContext Database BeginTransaction method

SQL logging output

SQL logging output

DbContext.Database.UseTransaction 

Sometimes we must use an existing transaction that is started outside of the Entity Framework. In this case the DbContext.Database.UseTransaction API is very useful. In this method we can pass an existing transaction object.

To maintain the transaction, the connection object must be the same, so we are required to create a DbContext contractor that takes a connection as an argument.
  1. public class EntitiesContext : DbContext  
  2. {  
  3.     public EntitiesContext()  
  4.         : base("name=Entities")  
  5.     {  
  6.         Database.Log = Console.WriteLine;  
  7.     }  
  8.     public EntitiesContext(DbConnection existingConnection, bool contextOwnsConnection)  
  9.         : base(existingConnection, contextOwnsConnection)  
  10.     {  
  11.   
  12.     }  
  13. }  
Test Code
  1. using(SqlConnection con = new SqlConnection("connectionString"))  
  2. {  
  3.     con.Open();  
  4.     using(var transaction = con.BeginTransaction())  
  5.     {  
  6.         // Do something....  
  7.   
  8.         //Pass this transaction to EF....  
  9.         using (EntitiesContext context = new EntitiesContext(con, false))  
  10.         {  
  11.             context.Database.UseTransaction(transaction);  
  12.             EmployeeMaster employee = new EmployeeMaster();  
  13.             employee.Code = "A0001";  
  14.             employee.Name = "Jignesh Trivedi";  
  15.             employee.DepartmentId = 1;  
  16.             context.Employees.Add(employee);  
  17.   
  18.             context.SaveChanges();  
  19.         }  
  20.     }  
  21. }  
Here the contextOwnsConnection flag must be set to false when we pass an open connection to the DBContext. This is very important because it informs the Entity Framework to not close the connection when it is done.

Summary
Entity Framework 6.0 introduced two new APIs to maintain transactions. The DbContext.Database.BeginTransaction API method creates a new transaction whereas the DbContext.Database.UseTransaction API method allows use of an existing transaction.

No comments :