使用Linq 更新数据库时遇到的一些问题及解决办法
2010-04-25 16:02
746 查看
前一段时间一直比较忙,没时间将自己在工作中总结的一些经验拿出来和大家分享。幸好今天有点时间,就写写吧。
在学习LINQ 时,我几乎被一个困难所击倒,这就是更新数据库的操作。
刚开始使用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作为更新检查依据。
在学习LINQ 时,我几乎被一个困难所击倒,这就是更新数据库的操作。
刚开始使用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作为更新检查依据。
相关文章推荐
- 使用Linq 更新数据库时遇到的一些问题及解决办法
- linq更新部分数据时遇到的问题及解决办法
- 项目适配iOS9遇到的一些问题及解决办法(持续更新)
- Caffe搭建:常见问题解决办法和ubuntu使用中遇到问题解决方法(持续更新)
- 生产环境使用elasticsearch遇到的一些问题以及解决方法(不断更新)
- 项目适配iOS9遇到的一些问题及解决办法(持续更新)
- 使用存储过程更新数据库!成功了但是返回值为 -1 的变态问题的解决办法!
- 生产环境使用elasticsearch遇到的一些问题以及解决方法(不断更新)
- 项目适配iOS9遇到的一些问题及解决办法(持续 c0f3 更新)
- 使用elasticsearch遇到的一些问题以及解决方法(不断更新)
- 使用Postgresql遇到的一些问题和解决办法
- 生产环境使用elasticsearch遇到的一些问题以及解决方法(不断更新)
- 项目适配iOS9遇到的一些问题及解决办法(更新两个小问题)
- 生产环境使用elasticsearch遇到的一些问题以及解决方法(不断更新)
- 项目适配iOS9遇到的一些问题及解决办法(更新两个小问题)
- Caffe搭建:常见问题解决办法和ubuntu使用中遇到问题解决方法(持续更新)
- 使用ZFPlayer过程中遇到的一些问题及解决办法
- 项目适配iOS9遇到的一些问题及解决办法(更新两个小问题)
- linq更新部分数据时遇到的问题及解决办法
- 项目适配iOS9遇到的一些问题及解决办法(更新两个小问题)