修改并发异常ChangeConfictException
//测试修改并发异常ChangeConfictException
var query = from p in ctx.Products
where p.CategoryID == 1
select p;
foreach (var p in query)
{
p.UnitsInStock = Convert.ToInt16(p.UnitsInStock - 1);
}
ctx.SubmitChanges();// 在这里设断点,程序运行到此处时,在数据库执行如下T_SQL操作
/* UPDATE dbo.Products SET UnitsInStock = UnitsInStock - 2 WHERE CategoryID=1 */
//然后继续运行程序,会抛出修改并发异常ChangeConfictException
/* 原因分析:当客户端提交的修改对象自读取之后已经在数据库中发生改动,就产生了修改并发。*/
/* 不考虑并发修改异常设置:实体类属性column特性增加UpdateCheck = UpdateCheck.Never
* 不考虑并发修改异常情况下,默认是最后一次更新起作用 */
处理修改并发异常ChangeConfictException
//处理修改并发异常ChangeConfictException
var query = from p in ctx.Products
where p.ProductID == 1
select p;
foreach (var p in query)
{
p.UnitsInStock = Convert.ToInt16(p.UnitsInStock - 1);
}
try
{
ctx.SubmitChanges(ConflictMode.ContinueOnConflict);
}
catch (ChangeConflictException)
{
foreach (ObjectChangeConflict cc in ctx.ChangeConflicts)
{
Products product = (Products)cc.Object;
cc.Resolve(RefreshMode.OverwriteCurrentValues);// 放弃当前进程更新,所有更新以原先其它进程更新为准
//cc.Resolve(RefreshMode.KeepCurrentValues); // 放弃原先其它进程更新,所有更新以当前进程更新为准
//cc.Resolve(RefreshMode.KeepChanges); // 原先其它进程更新有效,冲突字段以当前进程更新为准
}
}
ctx.SubmitChanges();
//针对不同策略处理不同字段修改并发异常ChangeConfictException
var query = from p in ctx.Products
where p.ProductID == 1
select p;
foreach (var p in query)
{
p.UnitsInStock = Convert.ToInt16(p.UnitsInStock - 1);
}
try
{
ctx.SubmitChanges(ConflictMode.ContinueOnConflict);
}
catch (ChangeConflictException)
{
//遍历并发冲突对象集合
foreach (ObjectChangeConflict cc in ctx.ChangeConflicts)
{
//遍历当前冲突对象更新失败的成员(即更新失败的列)
foreach (MemberChangeConflict mc in cc.MemberConflicts)
{
if (mc.Member.Name == "UnitsInStock")
{
mc.Resolve(RefreshMode.KeepCurrentValues); // 放弃原先其它进程更新,所有更新以当前进程更新为准
}
else if (mc.Member.Name == "UnitPrice")
{
mc.Resolve(RefreshMode.OverwriteCurrentValues); // 放弃当前进程更新,所有更新以原先其它进程更新为准
}
else
{
mc.Resolve(RefreshMode.KeepChanges); // 原先其它进程更新有效,冲突字段以当前进程更新为准
}
}
}
}
ctx.SubmitChanges();
事务:
//Linq to sql在提交更新的时候默认会创建事务,一部分修改发生错误的话其它修改也不会生效:
//假设数据库中已经存在顾客ID为“ALFKI”的记录,那么第二次插入操作失败将会导致第一次的插入操作失效。
ctx.Customers.InsertOnSubmit(new Customers { CustomerID = "abcdf", CompanyName = "zhuye" });
ctx.Customers.InsertOnSubmit(new Customers { CustomerID = "ALFKI", CompanyName = "zhuye" });
ctx.SubmitChanges();
使用事务
ctx.Connection.Open();
ctx.Transaction = ctx.Connection.BeginTransaction();
ctx.Customers.InsertOnSubmit(new Customers { CustomerID = "abcdf", CompanyName = "zhuye" });
ctx.Customers.InsertOnSubmit(new Customers { CustomerID = "ALFKI", CompanyName = "zhuye" });
try
{
ctx.SubmitChanges();
ctx.Transaction.Commit();
}
catch
{
ctx.Transaction.Rollback();
}
ctx.Connection.Close();
使用TransactionScope
using (TransactionScope tranScope = new TransactionScope())
{
ctx.Customers.InsertOnSubmit(new Customers { CustomerID = "abcdf", CompanyName = "zhuye" });
ctx.Customers.InsertOnSubmit(new Customers { CustomerID = "ALFKI", CompanyName = "zhuye" });
tranScope.Complete();
}