使用 LINQ 筛选多维条件
本文关键字:条件 筛选 LINQ 使用 | 更新日期: 2023-09-27 18:32:18
我正在尝试使用 LINQ 构建搜索查询,以利用用户传递的条件将其传递给实体框架。标准是二维的。
条件包括"字段名称"和"搜索运算符",例如:
字段名称可能包括"名字"、"姓氏"、"出生日期"、...等
搜索运算符可能包括"等于"、"开始为"、"结束于"、"更大"、...等
如您所见,有太多条件需要处理。实现代码的最佳方法是什么?
我当前的代码看起来像这样,但我觉得应该有更好的方法来做到这一点。
IQueryable<Employee> query = dbContext.Employee;
switch (FieldName)
{
case "FirstName":
switch (SearchOperator)
{
case "Equals":
query = query.Where(x => x.FirstName.Equals(SearchValue));
break;
case "BeginsWith":
query = query.Where(x => x.FirstName.StartsWith(SearchValue));
break;
}
break;
case "LastName":
switch (SearchOperator)
{
case "Equals":
query = query.Where(x => x.LastName.Equals(SearchValue));
break;
case "BeginsWith":
query = query.Where(x => x.LastName.StartsWith(SearchValue));
break;
}
}
您可以使用动态 linq:
查看文章:
http://weblogs.asp.net/scottgu/dynamic-linq-part-1-using-the-linq-dynamic-query-library。
使用动态 LINQ 可以执行以下操作:
switch (SearchOperator)
{
case "Equals":
query = query.Where(String.Format("{0}={1}",FieldName,SearchValue));
break;
case "Contains":
query = query.Where(String.Format("{0}.Contains({1})",FieldName,arrayOfSearchValues));
break;
case "StartsWith":
query = query.Where(String.Format("{0}.StartsWith({1})",FieldName,SearchValue));
break;
case "Greater":
query = query.Where(String.Format("{0}>{1}",FieldName,SearchValue));
break;
}
您可以在字典中保持动态过滤:
IQueryable<Employee> query = dbContext.Employee;
Dictionary<Tuple<string, string>, Func<Employee, string, bool>> _filter = new Dictionary<Tuple<string, string>, Func<Employee, string, bool>>()
{
{ new Tuple<string, string>("FirstName","Equals"), (x,s) => x.FirstName.Equals(s)},
{ new Tuple<string, string>("FirstName","BeginsWith"), (x,s) => x.FirstName.StartsWith(s)},
{ new Tuple<string, string>("LastName","Equals"), (x,s) => x.LastName.Equals(s)},
{ new Tuple<string, string>("LastName","BeginsWith"), (x,s) => x.LastName.StartsWith(s)},
};
public Employee Get()
{
Func<Employee, string, bool> filter = _filter.FirstOrDefault(k => k.Key.Item1 == FieldName && k.Key.Item2 == SearchOperator).Value;
return query.FirstOrDefault(e => filter(e, SearchValue));
}
因此,如果需要,它是可扩展的。
如果你不需要高性能或者你的数据库很小,你可以使用 IEnumerable 来链接 where 语句,如下所示:
IEnumerable<Employee> query = dbContext.Employee;
foreach(var searchOperator in searchOperators)
{
query = query.Where(n=> ....);
}
否则,您可以尝试构建表达式树。看看这里: Expression.Lambda 和运行时的查询生成,最简单的"Where"示例
例如:
var employee = Expression.Parameter(typeof(Employee), "employee");
var exprList = new List<BinaryExpression>();
foreach(var searchOperator in searchOperators)
{
switch(FieldName)
{
case "FirstName":
{
var property = Expression.Property(item, "FirstName");
switch(SearchOperator)
{
case "Equal":
var equalTo = Expression.Constant(SearchFirstName);
var expr = Expression.Equal(property, equalTo);
exprList.Add(expr);
break;
case "StartWith":
....
}
break;
}
}
}
var combined = exprList.Aggregate((n,m)=> Expression.And(n,m));
Expression<Func<Employee, bool>> expr = Expression.Lambda<Func<Item, bool>>(combined, employee);
var output = dbContext.Employee.Where(expr);
(我没有测试代码,它可能有错误,但我相信它应该或多或少看起来像这样)基本上,它更有效,因为实体框架通过遍历 Expression> 将查询转换为 SQL 查询。