ChangeConflictException:Row not found or changed 找不到行或行已更改

22 篇文章 0 订阅
12 篇文章 0 订阅

            系统日志中总是出现这个记录,网上搜罗了一下,有关linqtoSql的这个问题,有如下方案,尚未测试

原因:

    “.....,在正常运行状态下,Linq在运行时,会把数据库的数据缓存到实体对象中,这是一种理想化的情况,并且在更新时,Linq会默认把除更新字段外的所有字段,作为Update语句中的Where条件。但是,如果此时有另外的程序,在访问数据库,并修改数据库数据的时候,比如刚才把Age改为22。此时Linq缓存起来的数据和实际数据库中的数据产生了不一致的情况。Linq此时仍然把被修改过的字段,作为Update的Where条件,但是数据库中Age早就被我们改过了,不再是25,Where条件始终匹配不到原有的数据。这时,就会抛出所谓的:“System.Data.Linq.ChangeConflictException: Row not found or changed.”异常。“

   产生此异常,主要是Linq缓存数据和实际数据库数据不一致的情况造成。解决次问题的情况,主要有几种:
    1.比较简单的方法,不使用Linq提供的SubmitChanges()方式提交更改,而直接执行SQL语句,例如:
     db.ExecuteCommand("Update [dbo].[LinqTest] SET Age=25 Where ID = @p0", 1);
    这样虽然比较方便,但是感觉又回到了直接写SQL的时代,毕竟Linq to SQL的目的,就是为了让我们看不见SQL,避免写复杂的SQL语句,而直接操作实体对象,这样也可以避免程序可读性差、不便于维护。所以除非万不得已,还是不太推荐使用此方法。
    2.参考MSDN的资料,采用Linq提供的解决更新冲突的方法,在异常中捕获冲突,然后手动解决冲突:

try
{
    db.SubmitChanges(System.Data.Linq.ConflictMode.ContinueOnConflict);
}
catch (System.Data.Linq.ChangeConflictException ex)
{
    foreach (System.Data.Linq.ObjectChangeConflict occ in db.ChangeConflicts)
    {
         //以下是解决冲突的三种方法,选一种即可
        // 使用当前数据库中的值,覆盖Linq缓存中实体对象的值
        occ.Resolve(System.Data.Linq.RefreshMode.OverwriteCurrentValues);        
        // 使用Linq缓存中实体对象的值,覆盖当前数据库中的值
        occ.Resolve(System.Data.Linq.RefreshMode.KeepCurrentValues);        
        // 只更新实体对象中改变的字段的值,其他的保留不变
        occ.Resolve(System.Data.Linq.RefreshMode.KeepChanges);
    }
    // 这个地方要注意,Catch方法中,我们前面只是指明了怎样来解决冲突,这个地方还需要再次提交更新,这样的话,值    //才会提交到数据库。
    db.SubmitChanges();
}
3. 这个方法也比较简单,也即MSDN中所说的Pessimistic Concurrency Control  。 我们可以来设定哪些字段需要放入Where条件,哪些字段不需要,这样就可以控制更新时候的条件匹配尺度。具体做法,就是在Linq to SQL Designer中,把一些字段的UpdateCheck属性设置为Never,这样,这些字段在更新的时候,就不会再出现在Where条件中了。其实比较推荐的做法,就是在表中设立主键,因为更新的时候,只要把主键作为Where条件,就可以单独的确立一行数据了。把除主键外的字段属性中UpdateCheck设置为Never即可。

在使用Linq的当中遇到了"Row not found or changed",网上搜了很多也没有发现是什么原因。

我是取出一个实体对象然后改变其中的一些值,然后进行DataContext.SubmitChanges(),系统报这个错。

在我给这个表添加了三个字段之前这些都是运行的很好,自从我添加了那三个字段并做了一些读写操作然后就开始报这个错,

网上搜罗一下倒是有人提这个问题的解决方案:

在使用Linq的时候经常出现在了这样的一个错误
Row not found or changed. 找不到行或行已更改
解决方案。

如果不是重要的数据。不需要去理会并发重突。

一个简单的方案就是
打开dbml (linq)文件把实体类中的 属性 "Update check" 改为 Never.
主键(ID)就不要改了。

第二种方法. 不着征对一些记数情况的更新. 请直接用sql 语句,而不需要去取出整个数据然后再更新.这样就可能存在冲突了.

dC.ExecuteCommand("UPDATE [dbo].[MyTable] SET num=num+1 WHERE ID = @p0", m.ID);

第三种方法.

try
{
dc.SubmitChanges(System.Data.Linq.ConflictMode.ContinueOnConflict);
}
catch (System.Data.Linq.ChangeConflictException ex)
{

DC.ChangeConflicts.ResolveAll(RefreshMode.KeepCurrentValues); //保持当前的值

DC.ChangeConflicts.ResolveAll( RefreshMode.OverwriteCurrentValues);//保持原来的更新,放弃了当前的值.
DC.ChangeConflicts.ResolveAll(RefreshMode.KeepChanges);//保存原来的值 有冲突的话保存当前版本

// 注意:解决完冲突后还得 SubmitChanges() 一次,不然一样是没有更新到数据库的

db.SubmitChanges();
}

solution:
Open dbml (linq) file ,and find your entity change the propery(field) "update check " to Never

试了一下都不行。

后来又试了很多方式都不行,病急乱投医,问题肯定是出在我行添的那三个字段的问题上面,

于是我重点看了这三个字段,发现一个问题:

这三个字段在数据库中是可以为空的

但是在linq的定义中Nullable 定义为False

于是我把这三个字段都改为True,再试了一试,居然成功了。

这是为什么,有待继续研究。

注:要保持.dbml文件和数据库更新同步

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值