筛选 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 工作正常。
workOrders = workOrders.Where(filelist => filterList.Contains(filelist.Location)); //Returns only exact match
workOrders = workOrders.Where(filelist => filterList.Any(filter => filelist.Location.ToUpperInvariant().Contains(filter.ToUpperInvariant()))); //Returns error
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])...);
我想在不访问数据库的情况下使用 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 工作正常。
workOrders = workOrders.Where(filelist => filterList.Contains(filelist.Location)); //Returns only exact match
workOrders = workOrders.Where(filelist => filterList.Any(filter => filelist.Location.ToUpperInvariant().Contains(filter.ToUpperInvariant()))); //Returns error
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])...);