关于Linq查询条件可能为null时的诡异事件

By | 03月09日
Advertisement

群里一哥们有这样一个需求,有一张表结构如下:

  MenuId varchar(50) Unchecked
  MenuName varchar(50) Checked
  PatentMenuId varchar(50) Checked

测试数据如下:

 1 insert into MenuInfo values('100','父节点1',NULL)
 2 insert into MenuInfo values('101','子节点11','100')
 3 insert into MenuInfo values('102','子节点12','100')
 4 insert into MenuInfo values('103','子节点13','100')
 5 insert into MenuInfo values('104','父节点2',NULL)
 6 insert into MenuInfo values('105','子节点21','104')

这个表就不详细介绍了,相信大家都知道。

他的具体需求是根据一个字符串(strKey)作为条件查询,当strKey为null时,则只查出1和5这两条数据,如果strKey不为null时,则查出所有ParentMenuId为strKey的数据。

他原来的代码如下:

string strKey=null;

List<MenuInfo> menuList=new List<MenuInfo>();

if(strKey==null)

{

  menuList= (from menu in db.MenuInfo

         where menu.ParentMenuId==null

         select menu).ToList();

}

else

{

  menuList=(from menu in db.MenuInfo

        where menu.ParentMenuId==strKey

        select menu).ToList();

}

这样写肯定能实现前面说到的需求,现在就是如何去简化这段代码,即干掉if判断语句。

经过长时间激烈讨论,终于有人提出用三目表达式,代码如下:

string strKey=null;

List<MenuInfo> menuList=new List<MenuInfo>();

menuList=(from menu in db.MenuInfo

      where strKey==null?(menu.ParentMenuId==null: menu.ParentMenuId==strKey)

      select menu).ToList();

但是马上有人将其简化成以下代码:

string strKey=null;

List<MenuInfo> menuList=new List<MenuInfo>();

menuList=(from menu in db.MenuInfo

      where menu.ParentMenuId==(strKey==null?null:strKey)

      select menu).ToList();

到这里貌似没有问题了,讨论到此结束。

但是这哥们经过测试,最终还是发现了问题。当strKey为null时,却查不到任何数据。。。这是怎么回事呢?

后来这哥们把解析后的sql语句发出来一看,三目表达式确实有问题

当where 条件为 where menu.ParentMenuId==null 时,解析的sql条件为 WHERE [t0].[PatentMenuId] IS NULL

而当where条件为 where menu.ParentMenuId==strKey(此时strKey为null)时,解析的sql条件为 WHERE [t0].[PatentMenuId] = @p0

这又是为何?这时另一哥们发话了,原因是:为null的变量和null在linq语句中意义不同。

真是一语惊醒梦中人呀,很有可能是linq在解析的时候对null值进行了判断,这样就很好解释了。前面简化胡的三木运算表达式(strKey==null?null:strKey)返回的不一定是null值,所以linq解析的时候把它当成一个变量来处理了,没有判断其结果是不是为null,所以就直接解析成 WHERE [t0].[PatentMenuId] = @p0了。

可是笔者还是不甘心,回来查资料,又尝试了equals方法,代码如下:

string strKey=null;

List<MenuInfo> menuList=new List<MenuInfo>();

menuList=(from menu in db.MenuInfo

      where menu.PatentMenuId.Equals(strKey)

      select menu).ToList();

这样的结果跟前面用==的结果还是一样的,即:

当where 条件为 where menu.ParentMenuId.Equals(null) 时,解析的sql条件为 WHERE [t0].[PatentMenuId] IS NULL

而当where条件为 where menu.ParentMenuId.Equals(strKey)(此时strKey为null)时,解析的sql条件为 WHERE [t0].[PatentMenuId] = @p0

就这样胡乱尝试一通后又发现,由于menu.ParentMenuId是String类型,而String对象对Equals方法进行了重写,于是又一次尝试直接用object对象的Equals方法,简化成以下代码:

string strKey=null;

List<MenuInfo> menuList=new List<MenuInfo>();

menuList=(from menu in db.MenuInfo

      where Equals(menu.ParentMenuId,strKey)

      select menu).ToList();

终于搞定。但是这是为什么呢?

可能是string重写了equals,linq本身就对sting重写的equals方法制定了等同于“==”运算符的解析机制,而没有对object对象的equals方法制定机制。

用笔者自己的话来说,就是当用linq对象去主动比较其他对象的时候,会解析成linq对象=其他对象(@p0),结合前面那个哥们说的“为null的变量和null在linq语句中意义不同。”这个@p0虽然是C#变量值为null,但是与sql中的null不一样,所以在sql中这个where条件不成立,自然查不出数据。而用C#中object对象的Equals方法则不会解析成linq对象=其他对象@p0。

当然这些都还只是对实践结果的一种猜测,也是笔者在博客园上的处女作,欢迎园子里的前辈指点,也欢迎拍砖,谢谢大家支持。(*^__^*) 嘻嘻

Similar Posts:

  • 记录下butterfly 自定义查询(查询条件值是运行时输入)

    记录下butterfly 自定义查询(查询条件值是运行时输入) 步骤1: 新建一个查询,查询条件是运行时,即输入查询条件的值,然后点击确定就会查出满足条件的bo/sfo列表 步骤2:分析 点击确定后的按钮 .发现最终发送的页面参数如下: http://10.112.9.90:7080/butterfly/client?input_argument=true&sys_action=query&sub_action=new_exec&sys_event=input_args&q

  • LINQ查询条件为字段值在数组中

    int[] array = {20,10,11,...}; var result = from p in lqDB.Table1 where array.Contains(p.id) select p;

  • Linq使用Group By分析 Entity Framework 使用注意:Where查询条件中用到的关联实体不需要Include

    Linq使用Group By分析 http://www.aspww.cn/View/11060401.aspx Entity Framework 使用注意:Where查询条件中用到的关联实体不需要Include http://www.cnblogs.com/dudu/archive/2012/04/13/entity_framework_include_where.html 在Entity Framework 4中映射现有实体类(POCO) http://www.cnblogs.com/dudu

  • JDBC查询条件为中文时出错解决

    JDBC查询条件为中文时结果集为空,一直以为是程序的问题,但是在数据库中执行可以,最终发现出现这种问题的原因是MySQL的配置文件中默认字符集没有更改,由于有些Linux主机安装时自带MySQL,而安装的默认字符字不一定都是UTF-8,所以更改默认字符集其实很重要,DBA应该对号入座. 更改方法: 修改mysql的默认字符集是通过修改它的配置文件来实现的.一般分两种情况: [编辑] Windows平台 windows下的mysql配置文件是my.ini,一般在C:Program FilesMyS

  • Jqgrid在C#下的应用,使用LINQ查询结果集

    <link href="~/Styles/jquery-ui-1.9.0.custom.min.css" rel="stylesheet" type="text/css" /> <link href="~/Styles/ui.jqgrid.css" rel="stylesheet" type="text/css" /> <script src=".

  • ASP.NET 3.5核心编程学习笔记(21):LINQ查询语法

    从本质上讲,Linq-to-SQL能够将类与方法映射到数据源对象上. LINQ概述 大多数应用程序以某种数据仓库为中心.多年来,架构师在设计应用程序的过程中,一直通过对象对问题域进行建模.这些对象包括用于连接到数据访问层的连接,来艰难地与数据库进行交互,并通过对象模型建立关系模式.但这种方式对于简单的应用程序显得有些繁琐. LINQ的出现就是为了解决这些简单应用程序的需求,为其提供一套功能强大且易用的工具,能在更高的概念层上对数据存储进行操作. .NET 3.5版本中的编程语言能进行局部类型推断

  • 从索引技术谈数据库查询索引建立和查询条件书写

    索引的优势当然是提高检索速度,但并不是说数据库建立了索引就真的会提高检索速度.为什么呢? 我们知道,索引本身是有序的,索引查找的时候一般是多分查找,(当然在内存用数组实现的索引则可以做到随机查找,但数据库一般很少会采用这种方式组织,一般都是利用B+树),所以索引的查找一般不会是常数级,由于索引本身数据量问题,也不是一次就能将所有索引数据加载在内存里,所以也可能会引起多次磁盘读,加上定位到目标索引后还需要常数级的具体数据块磁盘读写,因此一次索引定位需要的磁盘读写可以控制在常数级别.因此索引查找的速

  • LinqToSql的问题 多条件 动态变化查询条件怎样查询

    发表于: 2012-04-13 11:24:58 C# code? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 StringBuilder sb = new StringBuilder(); sb.Append(" select * from feemain where 1=1"); if (cmb_sf.Text != "") sb.Append(" and wtdw='&quo

  • 利用Attribute特性简化多查询条件拼接sql语句的麻烦

    最近公司在做武汉公交信息化管理系统,做这种管理项目,最让人痛苦的就是表单的添加.修改.查询.添加.修改在我以前的文章中提到过,利用反射机制可以做到基本不写代码来完成.参见<ORM框架实现数据的自动绑定添加修改 <一>>.(不过遗憾的是,目前做的项目中没使用,还是在痛苦的写赋值语句) 上文中只是解决了添加.修改.显示列表的问题,但是在多关键字查询的时候就又要开始赋值和拼接字符串啦.为了偷懒和省去那些让人讨厌的烦琐事情俺就又开始想取巧的办法啦. 多关键字查询,一般的处理方法是,取出这些

  • linq查询语法和方法

    1. Select Select操作符对单个序列或集合中的值进行投影.下面的示例中使用select从序列中返回Employee表的所有列: using (NorthwindDataContext db=new NorthwindDataContext()) { //linq查询语法(基本语法) var query = from e in db.Employees where e.FirstName.StartsWith("M") select e; //linq方法语法(基本方法) v

Tags: