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

20
在这个帖子中,我学习了如何使用Linq的延迟执行来构建一个动态查询。但是该查询实际上使用的是WHERE条件的AND连接方式。 我该如何使用OR逻辑获得相同的查询结果? 由于Flags枚举值,查询应该检索UsernameWindowsUsername两者都有
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();
    }
}
2个回答

24

使用LINQKit的PredicateBuilder,您可以动态地构建谓词

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可以理解。

或者:如果没有它,表达式将被“Invoke”,这会导致EF抛出异常:

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

后来增加:

还有一种另类谓词生成器可以做到相同的效果,但是不使用Expand:http://petemontgomery.wordpress.com/2011/02/10/a-universal-predicatebuilder/


太棒了!完美运作! - Thomas Zweifel
有没有不需要第三方库的选项?(我更愿意避免使用第三方库带来的公司管理麻烦) - Zarepheth
@Zarepheth 这个“通用谓词构建器”几乎不算第三方库。它是你自己的代码库的一部分。在注释中给这个人以荣誉吧 :) - Gert Arnold
我必须在这个解决方案中使用 LINQKit 库 - 或者按照第二个链接选择另一个选项。然而,我继续搜索并安装了 Microsoft.Linq.Dynamic NuGet 包,它满足了我的需求。(来自 Microsoft 的免费软件通常不需要额外的手续)。 - Zarepheth
我本应该跟随那第二个链接;那是一个相对较小的类,我本可以将其复制到我的代码中。哦,好吧,现在我有了微软套件。 - Zarepheth

-2

这应该会有所帮助...

包含多列查询的问题

同时,表设计中似乎存在一个根本性的问题(如果我理解错了,请纠正我)。在您的数据库中,IdentifierType 的目的是什么?


IdentifierType不是DB的一部分。它只是告诉函数应该包括哪些列在WHERE条件中。 - Thomas Zweifel

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接