Linq解决更新冲突
来一个好网址, 微软官方的例子。 真搞不懂微软怎么不把资源好好理一下,找个东西真难。
http://msdn.microsoft.com/en-us/vcsharp/aa336746.aspx
首先来看一看一个代码:
NorthwindDataContext ctx = new NorthwindDataContext();
Customer alfki = ctx.Customers.Single(c => c.CustomerID == "ALFKI");
Console.WriteLine("Before update, the company name of Alfki is: " + alfki.CompanyName);
alfki.CompanyName = "New Company Name";
Customer newAlfki = ctx.Customers.Single(c => c.CustomerID == "ALFKI");
Console.WriteLine("Before submit changes, the company name of Alfki is: " + alfki.CompanyName);
ctx.SubmitChanges();
出来的代码肯定想不到。
Before update, the company name of Alfki is: Alfreds Futterkiste
Before submit changes, the company name of Alfki is: New Company Name
可以看到,第二次查询是在更新提交之前,这时候数据库中的值还没有改变,按理说这时候去进行数据库查询得到的值应该还是旧值,但是代码运行后发现查询出来的值确是更新后的值。这是为什么呢?其实原因还是上篇提到过的Identity Cache,DataContext以主键为key对数据对象进行缓存以此对数据对象的生命周期进行跟踪。借助Sql profile可以发现,第二次调用ctx.Customers.Single时,数据库并没有查询的记录,这里DataContext直接在内存中查找该对象并且返回。当然也可以关闭这种机制,只需要调用ctx.ObjectTrackingEnabled = false。DataContext就不再对数据对象进行Identity Cache,每次查询结果都是通过查询数据库得到。其实上面的这些跟更新没什么关系。但它主要是讲明了一个道理:当你在查询数据的时候得小心。因为很可能查到的是错误的数据。
数据库数据更新通常会遇到同步冲突的问题,比如获得数据以后,对数据进行一系列的操作,然后把新的数据更新回数据库。如果在数据进行操作的同时,有其它程序或者管理员改动了该数据的值,这样就会发生冲突。到底数据是应该保留现有的值呢还是把改动的值强行更新到数据库呢?Linq to SQL提供了很多方法来解决这种冲突问题。
还是一段简单的更新代码:
NorthwindDataContext ctx = new NorthwindDataContext();
Customer alfki = ctx.Customers.Single(c => c.CustomerID == "ALFKI");
alfki.CompanyName = "New Company Name";
ctx.SubmitChanges();
在SubmitChanges()加上断点然后运行,接着在数据库管理器中修改这条记录的CompanyName,最后回到vs界面,继续往下运行,这时会抛出ChangeConflictException,提示该行记录已经被删除或者被修改
在Linq to SQL中,解决冲突有几种方法:
- 在映射字段的Column Attribute中添加UpdateCheck属性
[Column(Storage="_CompanyName", DbType="NVarChar(40) NOT NULL", CanBeNull=false, UpdateCheck=UpdateCheck.Never)] public string CompanyName {
UpdateCheck的意思是在更新的时候是否检查冲突,分为三种,根据自己的需求进行选择:
- Always 始终检查
- Never 从不检查
- WhenChanged 当数据有改动的时候检查
2. 使用ObjectChangeConflict的Resolve方法,比如:
try { ctx.SubmitChanges(); } catch (ChangeConflictException) { foreach (ObjectChangeConflict confict in ctx.ChangeConflicts) { confict.Resolve(RefreshMode.KeepCurrentValues); } } finally { ctx.SubmitChanges(); }
这里RefreshMode就是表示解决冲突的方法,也有三种:
- KeepChanges 把改变过的属性值更新到数据库,没有改变过的属性值就用数据库的当前值
- KeepCurrentValues 把当前所有值更新到数据库 (用这个好像要好点)
- OverwriteCurrentValues 使用数据库的当前值,不做强行更新
文章写的很不错。 我加了一些个人的语言在里面。 现在园子里面LINQ好像不太活跃,大都是一些入门级别的文章。
如果LINQ用到实际项目中时会遇到很多问题, 不知园子里有没有一些讨论比较深的小组或团队呢。