Linq中的陷阱问题(折磨了好几天)

简介: Linq2SQL中一个经典的Exception Info: System.Data.Linq.ChangeConflictException异常过程。

最近在程序运行中,发生一个比较怪异的问题导致程序异常退出(崩溃),开始没注意,以为是偶发问题。后来变成了必再现问题。查看Windows事件日志异常如下:

Application: XXXXX.exe
Framework Version: v4.0.30319
Description: The process was terminated due to an unhandled exception.
Exception Info: System.Data.Linq.ChangeConflictException
Stack:
   at System.Data.Linq.DataContext.SubmitChanges(System.Data.Linq.ConflictMode)
   at NMS.PPC.DataSource.Database.DBOperator.SubmitChanges()

开始也没在意。觉得这个没什么,就是数据库更新时异常了。加个try-catch就解决了。结果发现另一个功能也发生了这个问题。由于Windows日志中没有抛出具体的Message,使用WinDebug分析Dump文件,看到了具体的消息,如下:

Exception object: 0000000010f87f48
Exception type:   System.Data.Linq.ChangeConflictException
Message:          找不到行或行已更改。
InnerException:   <none>

要更新的行明明存在怎么能找不到。我没更改呢,所以已更改不太可能发生。
因为研发环境无法再现,就将测试环境中的数据库和数据拿回到研发环境中,很快就再现了。确定问题确实存在。通过Linq输出SQL语句,发生所有的字段都在Where条件中出现了(这可能是Linq慢的原因吧)。
然后百度找到https://stackoverflow.com/questions/11189688/linq-to-sql-updating-without-refresh-when-updatecheck-never,说在Linq设计器将表列设置上UpdateCheck = Never。我是直接编码的,不用设计器。通过在DEMO程序中添加一个Linq设计,发现些设置在代码中就是在Column属性中加一个UpdateCheck即可。

[Column(UpdateCheck = UpdateCheck.Never)]
public double? AField{get;set;}

然后分析为什么旧的数据为什么出现,而新数据不出现。在分析崩溃原因时先不进行UpdateCheck = Never的设置。发现所有可空字段没设置值在Where条件中都是Is NULL判断。但AField却是=判断,但数据库中却没有值(将实例类字段值全输出发现AFiled居然有值)。
这个问题原因就找到了,确实按照Where条件查询不到记录了,异常也发生了。
然后到Linq实体类中去找代码,如下(代码中相关属性设置没添加):

private double? _AField;
public double? AField{
    get{
        if (_AFiled == null) return BField;
        return _AFiled;
    }
}

终于找到了原因,当AFiled是NULL时,直接取BField的值了,程序中确实对BField赋值了。
然后发现出问题的数据都是在此代码提交之前产生的数据,提交之后产生的数据正常。
总结
Linq2SQL中,如果是计算列,不用持久化到数据库中。所以可以不用加Column这个Attribute。
Linq2SQL中,Update时默认会把所有的持久化字段(即添加了Column这个Attribute的字段)作为Where条件,如果是在发布后的程序中添加新的非主键字段,建议在Column中添加上UpdateCheck = UpdateCheck.Never,这样在发布后更新旧的数据不会发生这种莫名的异常。

目录
相关文章
|
编译器 C语言
C语言编程陷阱:移植性
在编写可移植的C代码时,我们应考虑和应对可移植性缺陷,以确保代码能够在不同平台上正确运行。通过遵循C语言标准、了解特定平台的行为和使用标准库提供的函数等手段,可以减少可移植性问题的发生,并编写出更加健壮和可靠的C代码。同时,积极参与C语言社区和了解最新的C语言标准变化也是确保代码可移植性的重要方式。
140 0
|
5月前
|
安全 程序员 开发者
【程序员必看】汇编语言中的致命陷阱:如何避免那些让人夜不能寐的安全隐患?
【8月更文挑战第31天】编写安全的代码是每个程序员的目标,尤其在使用汇编语言时更为重要。本文探讨了汇编语言编程中常见的错误类型及预防措施。首先介绍了汇编语言的特点,然后详细分析了四种常见错误:越界内存访问、不当的数据类型转换、不正确的堆栈操作以及不安全的输入处理。每种错误均附有示例代码和具体预防措施,帮助开发者避免这些陷阱,提高代码安全性。通过遵循这些指导原则,可以显著降低错误发生率,确保程序的安全性和可靠性。
83 0
|
5月前
|
设计模式 程序员
故意把代码写得很烂,这样的 “防御性编程“ 可取吗?
故意把代码写得很烂,这样的 “防御性编程“ 可取吗?
|
6月前
|
设计模式 供应链 安全
面向对象方法的实践时可能的陷阱
【7月更文挑战第2天】本文介绍面向对象开发面临的问题:过度复杂性导致项目失败,如在库存管理系统中等。因此简化设计、合理使用继承、现实期望、适当选择设计模式和工具、以及提升团队技能是成功的关键。
131 1
面向对象方法的实践时可能的陷阱
|
XML 开发框架 .NET
C# | Linq基本功 —— 必学的必熟的10个方法
Linq(Language Integrated Query)是C#语言中的一种查询语言,它提供了一种统一的方式来查询和操作各种数据源,如集合、数据库、XML等。Linq的出现使得开发者能够以一种更简洁、更直观的方式来处理数据,提高了代码的可读性和可维护性。
145 0
|
Java Python
如何善用Java异常
Java的异常算是Java语言的一个特色了。也是在日常编码中会经常使用到的东西。但你真的了解异常吗?
138 0
|
缓存 小程序 Java
IntegerCache的妙用和陷阱!
考虑下面的小程序,你认为会输出为什么结果?
128 0
IntegerCache的妙用和陷阱!
|
存储 安全 Java
java编程思想第四版第十四章 类型信息总结
所有的类都是在对其第一次使用的时候,动态加载到JVM中的。当程序创建第一个对类的静态成员的引用时,就会加载这个类。这说明构造器也是类的静态方法。即使在构造器之前并没有static关键字,这个类也会被加载。
127 0
|
IDE 程序员 API
每个程序员都曾犯过的经典错误
人非圣贤,孰能无过。对于犯错,你不用太困扰,因为对开发者而言,犯错太正常不过,并且几乎每天都会发生。软件开发很难,因此错误或多或少总会发生。犯错可以接受。事实上,及时反思和总结错误才能使我们进一步成长。
|
安全 架构师 程序员
资本家“坑”程序员的 15 个陷阱
要开发软件,你就需要程序员。程序员又贵、又懒、又难以掌控。不管他们开发的软件行不行,你都要付他们钱。不管怎样,对你来说,能少付他们一点是一点,毕竟钱不是大风刮来的。问题是,他们有时候会发现你给得太少,索性就不干了。那么,该怎样避免这种情况呢?

热门文章

最新文章