如何使用多个'Where'表达式,并使用C#/.NET将它们与AND和OR链接在一起? [英] How to use multiple 'Where' expressions and chain them together with AND and OR using C#/.NET?

查看:103
本文介绍了如何使用多个'Where'表达式,并使用C#/.NET将它们与AND和OR链接在一起?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试在我的Web应用程序中创建一个过滤系统.问题是我不知道从客户端向API请求多少个过滤器.我已经构建好了,所以过滤器的数组来自像这样的单个字符串:?sizeFilters=big,small,medium

I am trying to make a filtering system in my web app. The problem is I don't know how many filters will be requested from my client to API. I've build it so the array of the filters comes from a single string like this: ?sizeFilters=big,small,medium

然后我使用string[] names = sizeFilters.Split(',');来获得像Where(x => x.listOfSizes.contains(names[index]));

我还需要使用AND和OR制作表达式的链,因为我将使用另一个过滤器,例如:'?typeFilters=normal,extra,spicy'

I need also to make the chain of the expression using AND and OR because I am gonna use another filter for example: '?typeFilters=normal,extra,spicy'

所以我需要使整个表达式看起来像这样,但可能要长几倍,它需要使用不同大小的数组:

So I need to make it that the whole expressions looks like this but it might be few times longer, it needs to work with different size of arrays:

退回物品Where size is big OR small OR medium AND Where type is normal OR extra OR spicy

Where(x => x.Sizes == "Small" || x => x.Sizes == "Medium" || x => x.Sizes == "Big" && 
x => x.Types == "normal" || x => x.Types == "extra" || x => x.Types == "Spicy")

推荐答案

最简单的选择就是使用表达式中的Enumerable.Contains来构建OR.并通过多次调用Where来构建AND.

The simplest option would be, as others have noted, to build your ORs using Enumerable.Contains within an expression; and to build your ANDs by calling Where multiple times.

// using these values as an example
string[] sizeTerms = /* initialize */;
string[] typeTerms = /* initialize */;

IQueryable<Item> items = /* initialize */
if (sizeTerms.Any()) {
    items = items.Where(x => sizeTerms.Contains(x.Size));
}
if (typeTerms.Any()) {
    items = items.Where(x => typeTerms.Contains(x.Type));
}

如果需要,可以将此逻辑包装到扩展方法中,该方法接受要过滤的表达式,并使用IEnumerable<string>表示过滤器值.并构造并应用Contains方法:

If you want, you could wrap this logic into an extension method that takes an expression to filter against, and an IEnumerable<string> for the filter values; and constructs and applies the Contains method:

// using System.Reflection
// using static System.Linq.Expressions.Expression

private static MethodInfo containsMethod = typeof(List<>).GetMethod("Contains");

public static IQueryable<TElement> WhereValues<TElement, TFilterTarget>(
        this IQueryable<TElement> qry, 
        Expression<Func<TElement, TFilterTarget>> targetExpr, 
        IEnumerable<string> values
) {
    var lst = values.ToList();
    if (!lst.Any()) { return qry; }

    return qry.Where(
        Lambda<Expression<Func<TElement, bool>>>(
            Call(
                Constant(lst),
                containsMethod.MakeGenericMethod(typeof(T)),
                targetExpr.Body
            ),
            targetExpr.Parameters.ToArray()
        )
    );
}

,可以这样称呼:

qry = qry
    .WhereValues(x => x.Size, sizeTerms)
    .WhereValues(x => x.Type, typeTerms);

一个警告:查询将基于传递给方法的值进行构建;如果以后进行了更改,则查询将不会反映这些更改.如果这是一个问题:

One caveat: the query will be built based on the values passed into the method; if they are later changed, the query won't reflect those changes. If this is an issue:

  • 获取Enumerable.Contains而不是List.Contains的适当重载,并且
  • 使用Expression.Call的重载生成一个静态方法调用,而不是实例方法调用.
  • get the appropriate overload of Enumerable.Contains, instead of List.Contains, and
  • use the overload of Expression.Call which produces a static method call, instead of an instance method call.

这篇关于如何使用多个'Where'表达式,并使用C#/.NET将它们与AND和OR链接在一起?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆