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即可。

原文:Timothy Ye的博客
原文地址:https://www.cnblogs.com/navigator/p/2917686.html