一起谈.NET技术,如何在项目中应用LinqToSql数据库事务
2011-09-02 00:19
681 查看
本文主要涉及LinqToSql数据库事务相关,文章不足之处,欢迎您指出。
一、回顾T-SQL中的事务机制
代码如下:
以上代码是一个具备事务机制的简单存储过程,需要指出的是当上述代码执行到第十行时,此时如果该存储过程未加入事务机制那么势必会导致第10行之前已经被影响的数据库记录也不会被还原(rollback)。这样的代码是我们不想见到的,所以事务在复杂的商业逻辑中保持数据的完整性还是尤为重要的。
二、LinqToSql 中的SubmitChanges内置事务机制
众所周知LinqToSql 中我们的事务机制代码变的相对简单了,如以下代码:
上述代码很容易理解,在LinqToSql 为了删除一条部门记录。我们首选要删除该部门被引用的外键表记录这里是员工表,(以上代码只是为举例用,实际开发中是不会有此种业务的)当外键记录都删除成功后代码执行到第8行,这时才能能删除部门对象。否则报SqlException外键引用无法删除部门记录。我们唯一需要做的只是将 DataContext.SubmitChanges();这句放在所有Linq操作数据库语句之后这样就可以调用数据库事务机制了。比如当第5行代码执行时SystemUser还被Order表引用。当SubmitChanges执行时会自动调用transaction.Rollback()方法回滚SubmitChanges()之前的所有被影响的数据库记录,详情请阅Reflector。
三、在LinqToSql中SubmitChange内置事务机制无法满足的业务场景
当程序需要处理更多更复杂的商业逻辑时,我发现光凭SubmitChange方法自带的事务机制是远远不能满足的。
该场景描述如下:
如果为完成某一个特定的业务,需要在程序中使用多次的SubmitChanges方法。比如我们要做一个库存相关业务,该业务是由两张表组成:主表+从表。分别为主表:Depot和从表:DepotDetail 两张表。两张表关系如下:
当我们通过LinqToSql生成一个库存对象时其实应先生成Depot对象后再将生成Depot对象的DepotID(主键)传递到DepotDetail对象中用于生成库存明细表记录。也就说为了生成库存明细表记录我们必须先生成Depot主表,那样就不得不先调用SubmitChanges方法,当保存DepotDetail对象时还需要再一次调用SubmitChanges()方法。因为调用了多次SubmitChanges方法所以SubmitChanges内置的回滚机制已经不能满足需要了。
四、TransactionScope的应用
我们需要引用.net 的System.Transactions 类库使用TransactionScope类,帮我们更有效的处理数据库事务机制。对TransactionScope进行封装,代码如下:
本段代码原作者,被我稍稍改造如下:
调用DBTransactionExtension代码如下:
根据上述调用方法,我们已经可以在LinqToSql中灵活的使用数据库事务了。
五、TransactionScope类使用的注意事项
使用TransactionScope时如果调用多次LinqToSql的DataContext对象实例(等同调用多个数据库连接),那么我们必须开启MSDTC否则事务不能正常工作,具体请阅MSDTC开启。注:TransactionScope 适用于多种 Data Provider 比如 oracle 、OleDB、ODBC等。
最后希望本篇文章能给您带来帮助。
一、回顾T-SQL中的事务机制
代码如下:
/*加入事务机制后的存储过程*/ create procedure sp_example @param1 int = null, @param2 nvarchar(20) = null as begin tran tranName /*sql 事务的加入*/ insert into table0 (col1,col2,col3) values ('value1','value2','value3') update table1 set column1 = @param1 where 1=1 --删除table2中一条已经被其他外键表引用的记录,此时会报sql引用错误 delete from table2 where column3 = @param1 insert into table3 (col1,col2) values ('value1','value2') if(@@error =0) commit tran tranName else rollback tran tranName go
以上代码是一个具备事务机制的简单存储过程,需要指出的是当上述代码执行到第十行时,此时如果该存储过程未加入事务机制那么势必会导致第10行之前已经被影响的数据库记录也不会被还原(rollback)。这样的代码是我们不想见到的,所以事务在复杂的商业逻辑中保持数据的完整性还是尤为重要的。
二、LinqToSql 中的SubmitChanges内置事务机制
众所周知LinqToSql 中我们的事务机制代码变的相对简单了,如以下代码:
public bool DeleteDepartment(int departmentId) { try { DataContext.SystemUser.DeleteOnSubmit( DataContext.SystemUser.FirstOrDefault(u => u.DepartmentID == departmentId)); DataContext.Department.DeleteOnSubmit( DataContext.Department.FirstOrDefault(f => f.DepartmentID == departmentId)); //事务机制被封装到SubmitChanges方法内 DataContext.SubmitChanges(); return true; } catch { return false; } }
上述代码很容易理解,在LinqToSql 为了删除一条部门记录。我们首选要删除该部门被引用的外键表记录这里是员工表,(以上代码只是为举例用,实际开发中是不会有此种业务的)当外键记录都删除成功后代码执行到第8行,这时才能能删除部门对象。否则报SqlException外键引用无法删除部门记录。我们唯一需要做的只是将 DataContext.SubmitChanges();这句放在所有Linq操作数据库语句之后这样就可以调用数据库事务机制了。比如当第5行代码执行时SystemUser还被Order表引用。当SubmitChanges执行时会自动调用transaction.Rollback()方法回滚SubmitChanges()之前的所有被影响的数据库记录,详情请阅Reflector。
三、在LinqToSql中SubmitChange内置事务机制无法满足的业务场景
当程序需要处理更多更复杂的商业逻辑时,我发现光凭SubmitChange方法自带的事务机制是远远不能满足的。
该场景描述如下:
如果为完成某一个特定的业务,需要在程序中使用多次的SubmitChanges方法。比如我们要做一个库存相关业务,该业务是由两张表组成:主表+从表。分别为主表:Depot和从表:DepotDetail 两张表。两张表关系如下:
当我们通过LinqToSql生成一个库存对象时其实应先生成Depot对象后再将生成Depot对象的DepotID(主键)传递到DepotDetail对象中用于生成库存明细表记录。也就说为了生成库存明细表记录我们必须先生成Depot主表,那样就不得不先调用SubmitChanges方法,当保存DepotDetail对象时还需要再一次调用SubmitChanges()方法。因为调用了多次SubmitChanges方法所以SubmitChanges内置的回滚机制已经不能满足需要了。
四、TransactionScope的应用
我们需要引用.net 的System.Transactions 类库使用TransactionScope类,帮我们更有效的处理数据库事务机制。对TransactionScope进行封装,代码如下:
本段代码原作者,被我稍稍改造如下:
1 public static class DBTransactionExtension 2 { 3 public static bool Excute(out string errorMsg, params Action[] actions) 4 { 5 //使用ReadCommitted隔离级别,保持与Sql Server的默认隔离级别一致 6 return Excute(out errorMsg, IsolationLevel.ReadCommitted, null, actions); 7 8 } 9 10 public static void Excute(out string errorMsg, IsolationLevel level, params Action[] actions) 11 { 12 Excute(out errorMsg, level, null, actions); 13 } 14 15 public static void Excute(out string errorMsg, int timeOut, params Action[] actions) 16 { 17 Excute(out errorMsg, IsolationLevel.ReadCommitted, timeOut, actions); 18 } 19 20 public static bool Excute(out string errorMsg, IsolationLevel level, int? timeOut, params Action[] actions) 21 { 22 errorMsg = ""; 23 if (actions == null || actions.Length == 0) 24 return false; 25 TransactionOptions options = new TransactionOptions(); 26 27 options.IsolationLevel = level; //默认为Serializable,这里根据参数来进行调整 28 29 if (timeOut.HasValue) 30 31 options.Timeout = new TimeSpan(0, 0, timeOut.Value); //默认60秒 32 33 using (TransactionScope tran = new TransactionScope(TransactionScopeOption.Required, options)) 34 { 35 try 36 { 37 Array.ForEach<Action>(actions, action => action()); 38 tran.Complete(); //通知事务管理器它可以提交事务 39 return true; 40 } 41 catch (Exception ex)//回滚事务 42 { 43 errorMsg = ex.Message; 44 return false; 45 } 46 } 47 } 48 49 }
调用DBTransactionExtension代码如下:
private void SaveDepot(Depot depot) { DataContext.Depots.InsertOnSubmit(depot); if (false)//TODO:保存库存主表前的逻辑判断,条件不满足时候调用 throw new exception执行TransactionScope回滚。 throw new Exception("自定义错误提示内容,最终由事务获取错误信息后抛给UI"); //条件满足则调用SubmitChanges DataContext.SubmitChanges(); DepotDetail depotDetail = new DepotDetail(); depotDetail.DepotID = depot.DepotID; depotDetail.Count = 100; DataContext.DepotDetails.InsertOnSubmit(depotDetail); //又调用了一次SubmitChanges DataContext.SubmitChanges(); } public Depot InvokeTransaction(Depot depot, out string errorMsg) { try { DBTransactionExtension.Excute(out errorMsg, () => SaveDepot(depot)); return depot; } catch (Exception ex) { errorMsg = ex.Message; return null; } }
根据上述调用方法,我们已经可以在LinqToSql中灵活的使用数据库事务了。
五、TransactionScope类使用的注意事项
使用TransactionScope时如果调用多次LinqToSql的DataContext对象实例(等同调用多个数据库连接),那么我们必须开启MSDTC否则事务不能正常工作,具体请阅MSDTC开启。注:TransactionScope 适用于多种 Data Provider 比如 oracle 、OleDB、ODBC等。
最后希望本篇文章能给您带来帮助。
相关文章推荐
- 一起谈.NET技术,如何将ASP.NET MVC2项目升级到MVC 3 RC
- 一起谈.NET技术,C# 枚举在项目中的应用总结
- 一起谈.NET技术,关于大型ASP.NET应用系统的架构—如何做到高性能高可伸缩性
- 一起谈.NET技术,HTTP协议及POST与GET操作差异,C#中如何使用POST、GET等
- 一起谈.NET技术,抛砖引玉:我看微软.NET各子技术领域之应用前景
- 一起谈.NET技术,十步教你ASP.NET MVC2项目升级MVC 3 RC
- [转]如何在.NET项目中应用DataTable对象
- 一起谈.NET技术,案例分析:Silverlight在中国人寿的应用
- 一起谈.NET技术,Visual Studio 2010中敏捷开发流程模板的应用
- 【转】如何在项目中应用LinqToSql数据库事务
- 一起谈.NET技术,ASP.NET 项目安装包制作(二)数据库安装、其他组件的安装
- 一起谈.NET技术,ASP.NET Eval如何进行数据绑定
- 一起谈.NET技术,反编译Silverlight项目
- 一起谈.NET技术,关于c#静态方法和实例方法的辨析和应用
- 一起谈.NET技术,WPF 基础到企业应用系列4——WPF千年轮回
- 一起谈.NET技术,Qt简介以及如何配置Qt使用VS2010进行开发
- 一起谈.NET技术,WPF 基础到企业应用系列2——WPF前世今生
- 一起谈.NET技术,如何解决分布式系统中的跨时区问题[原理篇]
- 一起谈.NET技术,WF4.0中如何实现XAML工作流的动态加载
- 一起谈.NET技术,应用Visual Studio 2010辅助敏捷测试(下)