Linq to Entities 中的动态 where 子句 (OR)

Posted

技术标签:

【中文标题】Linq to Entities 中的动态 where 子句 (OR)【英文标题】:Dynamic where clause (OR) in Linq to Entities 【发布时间】:2013-01-15 07:10:03 【问题描述】:

在here 的帖子中,我学习了如何使用 Linq 的延迟执行来构建动态查询。但查询实际上是使用 WHERE 条件的 AND 连接。

如何使用 OR 逻辑实现相同的查询?

由于 Flags 枚举,查询应该搜索 UsernameWindowsUsernameboth

public User GetUser(IdentifierType type, string identifier)

    using (var context = contextFactory.Invoke())
    
        var query = from u in context.Users select u;

        if (type.HasFlag(IdentifierType.Username))
            query = query.Where(u => u.Username == identifier);

        if (type.HasFlag(IdentifierType.Windows))
            query = query.Where(u => u.WindowsUsername == identifier);

        return query.FirstOrDefault();
    

【问题讨论】:

【参考方案1】:

使用LINQKit's PredicateBuilder 你可以build predicates dynamically。

var query = from u in context.Users select u;
var pred = Predicate.False<User>();

if (type.HasFlag(IdentifierType.Username))
    pred = pred.Or(u => u.Username == identifier);

if (type.HasFlag(IdentifierType.Windows))
    pred = pred.Or((u => u.WindowsUsername == identifier);

return query.Where(pred.Expand()).FirstOrDefault();
// or return query.AsExpandable().Where(pred).FirstOrDefault();

这就是Expand 的用途:

Entity Framework 的查询处理管道无法处理调用表达式,这就是您需要在查询中的第一个对象上调用 AsExpandable 的原因。通过调用 AsExpandable,您可以激活 LINQKit 的表达式访问者类,该类将调用表达式替换为 Entity Framework 可以理解的更简单的构造。

或者:没有它的表达式是Invoked,这会导致EF中的异常:

LINQ to Entities 不支持 LINQ 表达式节点类型“Invoke”。

后期添加:

有一个替代的谓词构建器可以做同样的事情,但没有展开:http://petemontgomery.wordpress.com/2011/02/10/a-universal-predicatebuilder/

【讨论】:

太棒了!完美运行! 是否有不需要第三方库的选项? (我希望避免我公司因使用 3rd 方库而产生的行政麻烦) @Zarepheth 这个“通用谓词构建器”几乎不是第三方库。它是您自己的代码库的一部分。只需在评论中给这个家伙学分:) 我必须在此解决方案中使用 LINQKit 库 - 或点击第二个链接到另一个选项。但是,我继续搜索并安装了满足我需求的Microsoft.Linq.Dynamic NuGet 包。 (微软的免费赠品通常是允许的,无需额外的繁文缛节)。 我应该关注第二个链接;这是一个相对较小的类,我可以复制到我的代码中。哦,好吧,我现在有 Microsoft 软件包。【参考方案2】:

这应该会有所帮助..

Contains Query on multiple columns

表的设计似乎也存在根本问题(如果我错了,请纠正我)。数据库中 IdentifierType 的用途是什么?

【讨论】:

IdentifierType 不是数据库的一部分。它只是告诉函数哪些列应该包含在 WHERE 条件中。

以上是关于Linq to Entities 中的动态 where 子句 (OR)的主要内容,如果未能解决你的问题,请参考以下文章

使用 Linq to Entities (EF6) 动态选择列名

在CQ中使用动态表达式在LINQ to Entities中使用INT列

LINQ to Entities 不支持 LINQ 表达式节点类型“Invoke”

LINQ to Entities OrderBy 表达式树

LINQ to Entities 中的“NOT IN”子句

将日期时间转换为 LINQ-to-entities 查询中的格式化字符串