当前位置:  开发笔记 > 编程语言 > 正文

将Linq中的可空类型与Sql进行比较

如何解决《将Linq中的可空类型与Sql进行比较》经验,为你挑选了4个好方法。

我有一个Category实体,它有一个Nullable ParentId字段.当下面的方法正在执行且categoryId为null时,结果似乎为null,但是有些类具有null ParentId值.

这里有什么问题,我错过了什么?

public IEnumerable GetSubCategories(long? categoryId)
{
    var subCategories = this.Repository.Categories.Where(c => c.ParentId == categoryId)
        .ToList().Cast();

    return subCategories;
}

顺便说一句,当我将条件更改为(c.ParentId == null)时,结果似乎正常.



1> ariel..:

另一种方式:

Where object.Equals(c.ParentId, categoryId)

要么

Where (categoryId == null ? c.ParentId == null : c.ParentId == categoryId)



2> Marc Gravell..:

首先要做的是进行日志记录,以查看生成的TSQL; 例如:

ctx.Log = Console.Out;

LINQ-to-SQL似乎稍微不一致地处理空值(取决于文字与值):

using(var ctx = new DataClasses2DataContext())
{
    ctx.Log = Console.Out;
    int? mgr = (int?)null; // redundant int? for comparison...
    // 23 rows:
    var bosses1 = ctx.Employees.Where(x => x.ReportsTo == (int?)null).ToList();
    // 0 rows:
    var bosses2 = ctx.Employees.Where(x => x.ReportsTo == mgr).ToList();
}

所以我所能建议的是使用带有空值的顶部形式!

Expression> predicate;
if(categoryId == null) {
    predicate = c=>c.ParentId == null;
} else {
    predicate = c=>c.ParentId == categoryId;
}
var subCategories = this.Repository.Categories
           .Where(predicate).ToList().Cast();

更新 - 我使用自定义"正常"工作Expression:

    static void Main()
    {
        ShowEmps(29); // 4 rows
        ShowEmps(null); // 23 rows
    }
    static void ShowEmps(int? manager)
    {
        using (var ctx = new DataClasses2DataContext())
        {
            ctx.Log = Console.Out;
            var emps = ctx.Employees.Where(x => x.ReportsTo, manager).ToList();
            Console.WriteLine(emps.Count);
        }
    }
    static IQueryable Where(
        this IQueryable source,
        Expression> selector,
        TValue? value) where TValue : struct
    {
        var param = Expression.Parameter(typeof (T), "x");
        var member = Expression.Invoke(selector, param);
        var body = Expression.Equal(
                member, Expression.Constant(value, typeof (TValue?)));
        var lambda = Expression.Lambda>(body, param);
        return source.Where(lambda);
    }


似乎没有更好的方法来处理这个问题.谢谢!
我会说文字和变量之间的不一致更糟,反直觉.谢谢你确认我的怀疑.+1
我遇到了这个完全相同的问题,做了同样的解决方法,并打算问是否有更好的方法来做到这一点.看起来没有:(这种行为真的反直觉.

3> Eric Petroel..:

我的猜测是,这是由于DBMS的一个相当常见的属性 - 仅仅因为两个都是空的并不意味着它们是相等的.

要详细说明,请尝试执行以下两个查询:

SELECT * FROM TABLE WHERE field = NULL

SELECT * FROM TABLE WHERE field IS NULL

"IS NULL"构造的原因是在DBMS世界中,NULL!= NULL,因为NULL的含义是该值未定义.由于NULL意味着未定义,因此您不能说两个空值相等,因为根据定义您不知道它们是什么.

当您显式检查"field == NULL"时,LINQ可能会将其转换为"field IS NULL".但是当你使用变量时,我猜测LINQ不会自动进行转换.

这是一篇MSDN论坛帖子,其中包含有关此问题的更多信息.

看起来好的"作弊"是将你的lambda改成这样:

c => c.ParentId.Equals(categoryId)


你需要使用对我来说有效的object.Equals(a,b),其中a.Equals(b)没有

4> algreat..:

您需要使用运算符Equals:

 var subCategories = this.Repository.Categories.Where(c => c.ParentId.Equals(categoryId))
        .ToList().Cast();

在以下情况下,等于可以为空的类型返回true:

HasValue属性为false,另一个参数为null.也就是说,根据定义,两个空值相等.

HasValue属性为true,Value属性返回的值等于另一个参数.

并返回false如果:

当前Nullable结构的HasValue属性为true,另一个参数为null.

当前Nullable结构的HasValue属性为false,另一个参数不为null.

当前Nullable结构的HasValue属性为true,Value属性返回的值不等于另一个参数.

更多信息Nullable <.T> .Equals Method


我在LinqPad中对此进行了测试,但这似乎不起作用。如果您输入'null'文字,则sql会生成您期望的测试Categories.ParentID为NULL。但是,如果您传入一个变量,它将测试Categories.ParentID = p0,如果p0为null,则该变量将无效。@ariel的object.Equals(Categories.ParentID,value)方法效果很好。
推荐阅读
凹凸曼00威威_694
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有