筛选 IQueryable,其中包含(%like%)List<string> 中的任何项目

Filter IQueryable which contains (%like%) any of the items in the List<string>

我想在不访问数据库的情况下使用 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,并且将在后期使用 Entity Framework.

使用 IQueryable 访问数据库

我已经尝试了这两个无效的代码,如果我排除我的试用代码(用于过滤属性、位置),我的 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'的节点必须return相同类型的非空值。或者,覆盖 'VisitLambda' 并将其更改为不访问此类子项。

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

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

我绝对没有测试过这个......但我认为如果你假装 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

我花了一段时间,但我用你的例子构建了一个有效的表达式树。

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

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

static Expression<Func<T, bool>> GetExpression<T>(string propertyName, List<string> propertyValue)
{
 Expression orExpression = null;
 var parameterExp = Expression.Parameter(typeof(T), "type");
 var propertyExp = Expression.Property(parameterExp, propertyName);

 foreach (string searchTerm in propertyValue)
 {
  MethodInfo method = typeof(string).GetMethod("Contains", new[] { typeof(string) });
  var someValue = Expression.Constant(searchTerm, typeof(string));
  var containsMethodExp = Expression.Call(propertyExp, method, someValue);

  if(orExpression == null) //to handle intial phase when left expression = null
  {
   orExpression = Expression.Call(propertyExp, method, someValue);
  }else
  {
   orExpression = Expression.Or(orExpression, containsMethodExp);
  }
  return Expression.Lambda<Func<T, bool>>(orExpression, parameterExp);
}


myQueryable = myQueryable.Where(GetExpression<Workorder>(property, filterList));

这等于:

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