Linq to SQL 的更新冲突与管理默认分类 2011-01-15 17:37:35 阅读11 评论0 字号:大中小 订阅 前段时间工作中的一个新需求,有机会用到了Linq to SQL。使用后的第一感觉,就是方便很多,也为整个项目节约了一大把的开发时间,甚至代码量也少了很多。不过在程序的实际运行中,始终会遇到一些莫名其妙的异常,最令人不解的,就是“System.Data.Linq.ChangeConflictException: Row not found or changed.” 。当初凭自己和同事的判断,可能是数据库的数据异常所导致,后来发觉这个异常出现得越来越频繁,于是上MSDN查了查,原来是Linq中一个常见的问题:更新冲突。 1: namespace LinqTest 2: {
3: class Program 4: {
5: static void Main(string[] args) 6: {
7: TestDataContext db = new TestDataContext(); 8: db.Log = Console.Out;
9: var result = from p in db.LinqTests 10: where p.ID == 1 11: select p;
12: var info = result.FirstOrDefault();
13: if (info != null) //插入断点 14: {
15: info.Age = 25;
16: db.SubmitChanges();
17: }
18: Console.ReadLine();
19: }
20: }
21: }
在测试代码中,将DataContext的日志定向到Console的输出部分,这样方便我们观察Linq实际执行的SQL语句是什么。重现的时候,我们需要在注释的地方,插入断点进行测试。对于示例中的代码,在正常情况下,是不会有错误的。执行过后,我们可以在Console的输出中,看到实际执行的SQL语句(如图) 1: try 2: {
3: db.SubmitChanges(System.Data.Linq.ConflictMode.ContinueOnConflict);
4: }
5: catch (System.Data.Linq.ChangeConflictException ex) 6: {
7: foreach (System.Data.Linq.ObjectChangeConflict occ in db.ChangeConflicts) 8: {
9: //以下是解决冲突的三种方法,选一种即可 10: //使用当前数据库中的值,覆盖Linq缓存中实体对象的值 11: occ.Resolve(System.Data.Linq.RefreshMode.OverwriteCurrentValues);
12: //使用Linq缓存中实体对象的值,覆盖当前数据库中的值 13: occ.Resolve(System.Data.Linq.RefreshMode.KeepCurrentValues);
14: //只更新实体对象中改变的字段的值,其他的保留不变 15: occ.Resolve(System.Data.Linq.RefreshMode.KeepChanges);
16: }
17: //这个地方要注意,Catch方法中,我们前面只是指明了怎样来解决冲突,这个地方还需要再次提交更新,这样的话,值 //才会提交到数据库。 18: db.SubmitChanges();
19: }
3. 这个方法也比较简单,也即MSDN中所说的Pessimistic Concurrency Control 。 我们可以来设定哪些字段需要放入Where条件,哪些字段不需要,这样就可以控制更新时候的条件匹配尺度。具体做法,就是在Linq to SQL Designer中,把一些字段的UpdateCheck属性设置为Never,这样,这些字段在更新的时候,就不会再出现在Where条件中了。其实比较推荐的做法,就是在表中设立主键,因为更新的时候,只要把主键作为Where条件,就可以单独的确立一行数据了。把除主键外的字段属性中UpdateCheck设置为Never即可。 |
|