前段时间事情中的一个新需求,有机会用到了Linq to SQL。使用后的第一觉得,就是便利很多,也为整个项目节约了一大把的开发时间,甚至代码量也少了很多。不过在措施的实际运行中,始终会遇到一些莫名其妙的异常,最令人不解的,就是System.Data.Linq.ChangeConflictException: Row not found or changed. 。当初凭本身和同事的判断,可能是数据库的数据异常所导致,后来觉察这个异常呈现得越来越频繁,于是上MSDN查了查,本来是Linq中一个常见的问题:更新斗嘴。
这个词说起来对照玄乎,其实再泛泛不过了。下面可以通过一个简单的例子,来重现这个异常。
成立一个普通的测试表:LinqTest(如图)
在测试表中,插入一条测试数据(如图)
测试代码如下:
在测试代码中,将DataContext的日志定向到Console的输出部分,这样便利我们不雅察看Linq实际执行的SQL语句是什么。重现的时候,我们需要在注释的处所,插入断点进行测试。对付示例中的代码,在正常情况下,是不会有错误的。执行过后,我们可以在Console的输出中,看到实际执行的SQL语句(如图)
再进行第二次调试,首先,恢复Age的数据到以前的样子。下面我们运行到断点处,然后偷偷去SQL Server Management Studio中,手动改削数据,将原始数据中的Age,由24,改为22。然后回到VS2008的IDE,按F5继续运行措施,这个时候,你会发明异常呈现了(如图)
再回到Console的输出,检察,执行的SQL语句和适才的一样。这就是问题的地址,在正常运行状态下,,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 to SQL中如何打点变动斗嘴的更多资料,可以在MSDN找到
标签:
原文地点:https://www.cnblogs.com/bdqczhl/p/8817924.html