将 IQueryableWhere() 扩展为 OR 而不是 AND 关系

2023-12-23

我正在使用我自己的 IQueryable 扩展方法来创建可链接查询,例如 FindAll().FindInZip(12345).NameStartsWith("XYZ").OrderByHowIWantIt() 等,然后在延迟执行时根据我的创建一个查询扩展方法链。

但问题是,扩展链中的所有位置(FindXYZ、FindInZip 等)将始终组合为 AND,这意味着我不能执行以下操作:

FindAll().FirstNameStartsWith("X").OrLastNameStartsWith("Z") 因为我不知道如何在单独的Where方法中注入OR。

知道我该如何解决这个问题吗?


额外的; 到目前为止,我了解如何将表达式链接为 Or 如果我包装它们(例如 CompileAsOr(FirstName StartsWith("A").LastName StartsWith("Z").Order By(..))

我想做的事情稍微复杂一些(PredicateBuilder 在这里没有帮助..),因为我希望稍后的 IQueryable 基本上访问之前建立的Where条件,而不必包装它们来创建 Or 之间的条件他们。

当每个扩展方法返回 IQueryable 时,我知道它应该了解某处查询条件的当前状态,这使我相信应该有某种自动化的方法或在所有先前的 Where 条件中创建 Or ,而不必换行你想要什么Ord。


我假设查询的不同部分仅在运行时才知道,即您不能只使用|| in a where...

一种懒惰的选择是Concat- 但这往往会导致 TSQL 等性能不佳;但是,我倾向于编写自定义的Expression代替。采取的方法取决于提供程序是什么,因为 LINQ-to-SQL 支持 EF 的不同选项(例如) - 这在这里具有真正的影响(因为您不能在 EF 中使用子表达式)。你能告诉我们是哪一个吗?


下面是一些应该与 LINQ-to-SQL 一起使用的代码;如果你构建一个数组(或列表,并调用.ToArray()) 的表达式,应该可以正常工作;示例是 LINQ-to-Objects,但应该仍然有效:

    static void Main()
    {
        var data = (new[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }).AsQueryable();

        var predicates = new List<Expression<Func<int, bool>>>();
        predicates.Add(i => i % 3 == 0);
        predicates.Add(i => i >= 8);           

        foreach (var item in data.WhereAny(predicates.ToArray()))
        {
            Console.WriteLine(item);
        }
    }

    public static IQueryable<T> WhereAny<T>(
        this IQueryable<T> source,
        params Expression<Func<T,bool>>[] predicates)
    {
        if (source == null) throw new ArgumentNullException("source");
        if (predicates == null) throw new ArgumentNullException("predicates");
        if (predicates.Length == 0) return source.Where(x => false); // no matches!
        if (predicates.Length == 1) return source.Where(predicates[0]); // simple

        var param = Expression.Parameter(typeof(T), "x");
        Expression body = Expression.Invoke(predicates[0], param);
        for (int i = 1; i < predicates.Length; i++)
        {
            body = Expression.OrElse(body, Expression.Invoke(predicates[i], param));
        }
        var lambda = Expression.Lambda<Func<T, bool>>(body, param);
        return source.Where(lambda);
    }
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

将 IQueryableWhere() 扩展为 OR 而不是 AND 关系 的相关文章

随机推荐