使用Linq 更新数据库时遇到的一些问题及解决办法
2010-05-30 01:45 Andy Ge 阅读(1231) 评论(1) 编辑 收藏 举报刚开始使用Linq,对linq 的更新策略还不是很了解,所以在设计数据库的时候根本就没有考虑到更新检查策略。在插入的时候没有任何问题,更新数据的时候,问题就来了,报错:“System.Data.Linq.ChangeConflictException: Row not found or changed”(找不到行或行已更改)。在网上查了下,这个问题有两种解决办法:一是增加 timestamp(时间戳)列,二是设置主键 IsVersion="true"。我选用了第二种解决办法,OK,更新数据库没有问题了。但是,插入的时候报错:“主键不能插入NULL值”,设置断点,单步跟踪,直到 SubmitChanges()之前,都是有值的,执行SubmitChanges()方法,就报上面的错误。无奈,我决定使用第二种解决办法:设置timestamp列,OK,插入和更新都不报错了。
下面我来简单说一下Linq的更新检查策略。
在正常运行状态下,Linq在运行时,会把数据库的数据缓存到实体对象中,所以我们更新数据的时候,并不是直接更新数据库,而是更新缓存中的数据,然后将更改提交到数据库。Linq采用了一种叫做“乐观式并发”的策略。乐观式并发允许任意多的用户随时修改他们自己的一份数据的拷贝。在提交修改时,程序将检查以前的数据是否有所改变。若没有变化,则程序只需保存修改即可。若发生了变化并存在冲突,那么程序将根据实际情况决定是将前一修改覆盖掉,还是把这一次新的修改丢弃,或是尝试合并两次修改。乐观式并发的前一半操作相对来说比较简单。在不需要并发检查的情况下,数据库中使用的SQL语句将类似于如下语法:UPDATE TABLE SET [field = value] WHERE [Id = value]。不过在乐观式并发中,Where子句将不只包含ID列,同时还要比较表中其他各列是否与原有值相同,Linq会默认把除更新字段外的所有字段,作为Update语句中的Where条件。 在调用DataContext的SubmitChanges方法时,LINQ将生成上述Update语句并发送给数据库处理。若这条语句并没有更新数据库中的任意一行,那么DataContext就得知更新过程中产生了冲突,于是抛出“找不到行或行已更改”异常。实际使用中,若用来实现乐观式并发的参数数量过多,可能会导致一些性能上的问题。在这种情况下,我们可以借助UpdateCheck来修改映射规则,只让对象中的一部分属性参与到乐观式并发检查中。在默认情况下,属性的UpdateCheck将设置为Always,即表示LINQ to SQL将用该属性检查乐观式并发。我们可以根据需要将其调整为只在该属性值发生改变时才检查(WhenChanged),或是从不使用该属性进行检查(Never)。
若在数据表中有timestamp 列,其它列(主键除外)的UpdateCheck属性会默认设置为Never,若使用IsVersion作为更新检查依据,则必须在字段上手动设置UpdateCheck.Never属性来避免更新检查,但是如果数据表更新、新增存储过程,需要重新生成dbml的话,你在字段上设置的IsVersion和UpdateCheck.Never都将消失不见,你需要手动重新设置一遍,真是烦不胜烦,所以我推荐使用timestamp作为更新检查依据。
(转自 http://blog.csdn.net/zhangyumei/archive/2010/04/25/5526873.aspx)