Linq To SQL支持三种事务处理模型:显式本地事务、显式可分发事务、隐式事务。
1.显式本地事务
SubmitChanges只能处理最基本的CUD(Create/Update/Delete)操作;而在日常的应用中,逻辑往往没有这么简单,或者考虑性能等因素,我们需要配合ADO.Net执行原生的TSQL;这时我们可能要让ADO.Net+ Linq to SQL来进行配合处理。
代码:
public static void TestTranInSQL2008()
{
using(SqlConnection conn = new SqlConnection(Settings.Default.AdventureWorksConnectionString))
{
conn.Open(); //1. 创建并打开DbConnection连接
using (SqlTransaction tran = conn.BeginTransaction()) //2. 开启DbTransaction
{
//3. 使用ADO.Net执行TSQL
SqlCommand cmd = new SqlCommand("Update TLinq SET Value=10", conn, tran);
cmd.ExecuteNonQuery();
//4. 配合Ado.Net和Linq to Sql: 将ADO.Net的DbConnection和DbTransaction传给Linq to Sql
using (AdventureWorksDataContext context1 = new AdventureWorksDataContext(conn))
{
context1.Transaction = tran;
List<TLINQ> linq = context1.TLINQ.ToList();
context1.TLINQ.InsertOnSubmit(new TLINQ() { Value = "1" });
linq.ForEach(e => e.Value = (Convert.ToInt32(e.Value) + 1).ToString());
context1.SubmitChanges();
}
tran.Commit(); //5. 需要提交手工创建的事务
}
}
}
2.显式可分发事务
使用TransactionScope来进行显示可分发事务控制。TransactionScope就像事务处理里面的一面魔镜,如果需要事务,就对着它喊:“主啊,请赐我事务!”,于是这个操作就有了事务功能。关于TransactionScope的详细介绍,可以参考MSDN:使用事务范围实现隐式事务,及SQL Server的联机丛书:CLR 集成和事务。
代码:
public static void TestTransactionScopeInSQL2008()
{
Action action = () => //1.把要执行的操作封装在一个或多个Action中
{
using (AdventureWorksDataContext context1 = new AdventureWorksDataContext())
{
context1.ExecuteCommand("Update TLinq SET Value={0}", 10);
List<TLINQ> linq = context1.TLINQ.ToList();
context1.TLINQ.InsertOnSubmit(new TLINQ() { Value = "1" });
linq.ForEach(e => e.Value = (Convert.ToInt32(e.Value) + 1).ToString());
context1.SubmitChanges();
}
};
TransactioExtension.Excute(action);
}
3.隐式事务
当调用SubmitChanges 时,L2S会检查当前环境是否开启了事务(下面两节中创建的事务),如果没有开始事务,则 L2S启动本地事务(IDbTransaction),并使用此事务执行所生成的 SQL 命令。
使用Reflector查看DataContext.SubmitChanges的源代码(见本文最后的附录),可以看到,如果开启了一个事务,并将其传给DataContext.Transaction,则在执行SubmitChanges时就不会再重新开启一个新的事务了。
代码:
public static void TestTranIn2000()
{
using (SQL2000.Sql2000DataContext context1 = new SQL2000.Sql2000DataContext())
{
List<SQL2000.TLINQ> linq = context1.TLINQ.ToList();
linq.ForEach(e => e.Value += e.Value);
context1.SubmitChanges();
}
}