首页 > 解决方案 > 过滤包含 (%like%) 列表中任何项目的 IQueryable

问题描述

我想在不访问数据库的情况下使用 List 过滤 IQueryable/List。IQueryable 结果应包括包含列表中任何字符串的所有结果,并且列表的长度未指定。

myQueryable = myQueryable.Where(filelist => filelist.Location.Contains(filterList[0]) || filelist.Location.Contains(filterList[1]) || filelist.Location.Contains(filterList[N])...);

我正在使用 ASP.NET Core 3,并将使用 IQueryable 在稍后阶段使用 Entity Framework 访问数据库。

我已经尝试了这两个不起作用的代码,如果我排除我的试用代码(用于过滤属性、位置),我的 IQuery 工作正常。

  1. workOrders = workOrders.Where(filelist => filterList.Contains(filelist.Location)); //Returns only exact match

  2. workOrders = workOrders.Where(filelist => filterList.Any(filter => filelist.Location.ToUpperInvariant().Contains(filter.ToUpperInvariant()))); //Returns error

  3. Expression<Func<Workorder, bool>> predicate = filelist => false; foreach (var filter in filterList) { Expression<Func<Workorder, bool>> orPredicate = filelist => filter.Contains(filelist.Location); var body = Expression.Or(predicate.Body, orPredicate.Body); predicate = Expression.Lambda<Func<Workorder, bool>>(body, predicate.Parameters[0]); } workOrders = workOrders.Where(predicate); //Returns Error

class Workorder //Database Model
{
        public string SiteId { get; set; }      
        public string Location { get; set; }        
}

List<string> filterList //List to be used as filter
{
        "filterOne",
        "filterTwo",
        "filterN"          
};

我运行的第二个代码给了我一个错误,我什么也得不到。

System.InvalidOperationException:从“VisitLambda”调用时,重写“System.Linq.Expressions.ParameterExpression”类型的节点必须返回相同类型的非空值。或者,覆盖“VisitLambda”并将其更改为不访问此类型的子项。

我运行的第三个代码给了我这个错误,

System.InvalidOperationException:由于对象的当前状态,操作无效。在 Microsoft.EntityFrameworkCore.Relational.Query.Pipeline.RelationalQueryableMethodTranslatingExpressionVisitor.TranslateWhere(ShapedQueryExpression 源,LambdaExpression 谓词)

标签: c#listlambdafilteriqueryable

解决方案


我绝对没有测试过这个......但我认为如果你假装 EF 事后解析它,你不能用单线来做到这一点。

但是,这样的事情应该没问题:

Expression<Func<WorkOrder, bool>> predicate = filelist => false;
foreach(var filter in filterList) {
    Expression<Func<WorkOrder, bool>> orPredicate = filelist => filter.Contains(filelist.Location);
    var body = Expression.Or(predicate.Body, orPredicate.Body);
    predicate = Expression.Lambda<Func<WorkOrder,bool>>(body, predicate.Parameters[0]);
}

进而:

myQueryable = myQueryable.Where(predicate);

我们基本上只是告诉它:

.Where(filelist => false || filterList[0].Contains(filelist.Location) || filterList[1].Contains(filelist.Location) || ...);

编辑

仍未在 EF 上测试,但至少语法似乎没问题:https ://dotnetfiddle.net/Htr7Zr


推荐阅读