EF中使用事務
這節介紹EF6中事務的使用。EF core中事務的使用方式和EF6中一模一樣。
1.EF中的默認的事務
默認情況下,當我們執行一個SaveChanges()方法時就會新建了一個事務,然后將context中的CUD操作都在這個事務中進行。Context中有多個SaveChanges()時,每一個SaveChanges()都會執行一個單獨的事務。一個栗子:
using (var context = new SchoolContext()) { context.Database.Log = Console.Write; var standard = context.Standards.Add(new Standard() { StandardName = "1st Grade" }); context.Students.Add(new Student() { FirstName = "Rama", StandardId = standard.StandardId }); context.SaveChanges(); context.Courses.Add(new Course() { CourseName = "Computer Science" }); context.SaveChanges(); }
上邊的代碼執行結果如下:
從上邊的栗子我們可以清楚地看到每個SaveChanges()方法都開啟了一個事務。這時有一個問題:有沒有什么辦法讓多個SaveChanges()在一個事務中執行呢?這樣的話就可以減少事務創建、開啟進而提升性能了。
2.一個事務執行多個SaveChanges()方法
EF6和EF core中提供了兩種方法實現在一個事務中執行多個SaveChanges()方法。
① DbContext.Database.BeginTrasaction():新建一個事務,在新建的事務內進行context.SaveChanges()
②DbContext.Database.UseTransaction(trans):使用一個context作用域外的現有的事務,多個context都可以在通過這個事務一起提交。
1.DbContext.Database.BeginTrasaction()
一個栗子:
using (var context = new SchoolContext()) { context.Database.Log = Console.Write; using (DbContextTransaction transaction = context.Database.BeginTransaction()) { try { var standard = context.Standards.Add(new Standard() { StandardName = "1st Grade" }); context.Students.Add(new Student() { FirstName = "Rama", StandardId = standard.StandardId }); context.SaveChanges(); // 第一個SaveChanges()方法后拋出異常 throw new Exception(); context.Courses.Add(new Course() { CourseName = "Computer Science" }); context.SaveChanges(); transaction.Commit(); } catch (Exception ex) { transaction.Rollback(); Console.WriteLine("Error occurred."); } } }
執行結果:
我們可以看到所有的SaveChanges()都被回滾了。如果把拋出異常的代碼注釋掉那么執行效果如下:
2.DbContext.Database.UseTransaction(trans)
使用DbContext.Database.UseTransaction(trans),我們通過參數傳入的是一個作用域外的事務,注意:這里EF不會再新建內置的事務,而是使用通過參數傳入的事務。
一個栗子:
private static void Main(string[] args) { string providerName = "System.Data.SqlClient"; string serverName = "."; string databaseName = "SchoolDB"; // 目標數據庫 SqlConnectionStringBuilder sqlBuilder =new SqlConnectionStringBuilder(); sqlBuilder.DataSource = serverName; sqlBuilder.InitialCatalog = databaseName; sqlBuilder.IntegratedSecurity = true; using (SqlConnection con = new SqlConnection(sqlBuilder.ToString())) { con.Open(); //在DbContext作用域外新建一個事務 using (SqlTransaction transaction = con.BeginTransaction()) { try { //使用上邊的創建的事務 using (SchoolContext context = new SchoolContext(con, false)) { context.Database.UseTransaction(transaction); context.Students.Add(new Student() { Name = "Ravi" }); context.SaveChanges(); } using (SchoolContext context = new SchoolContext(con, false)) { context.Database.UseTransaction(transaction); context.Grades.Add(new Standard() { GradeName = "Grade 1", Section = "A" }); context.SaveChanges(); } transaction.Commit(); } catch (Exception ex) { transaction.Rollback(); Console.WriteLine(ex.InnerException); } } } }
EF系列目錄鏈接:Entity Franmework系列教程匯總