通过 lambdas 构造 where 的表达式
Construct expression for where through lambdas
情况
我有一个接受 POCO 的方法。这个POCO长这样
private class SearchCriteria
{
public string name get;set;
public string age get;set;
public string talent get;set;
..
....
}
该方法主要是对使用上述条件的数据库进行查询。
public void query(SearchCriteria crit)
{
if(crit.name!=null && crit.age!=null && crit.talent !=null)
{
dbContext.Students.Where(c=>c.name ==crit.name && c.age==crit.age...)
}
else if(crit.name !=null && crit.age!=null)
{
}
else if(....
{
}
正如您所看到的,上面有一个明确的问题,在大量条件的情况下,我将不得不编写大量的 if-elses 来从 where 子句中删除特定的参数。
可能的解决方案?
我实际上是 lambda 表达式世界的新手,但我相信我们一定有一个设施可以让我们做如下的事情。
dbContext.Students.Where(processCriteria(searchCriteriaPOCO))
.
你们能指引我正确的方向吗?。谢谢
也许我遗漏了什么,因为代码示例不是我见过的最清晰的,但是对于您的具体示例,我认为以下内容应该没问题:
dbContext.Students.Where(c => (crit.name == null || crit.name == c.name) &&
(crit.age == null || crit.age == c.age) &&
(crit.talent == null || crit.talent == c.talent));
无需链接一堆 if
语句。
对于更复杂的场景,您可能更喜欢 PredicateBuilder
您可以使用这样的模式:
dbContext.Students.Where(c=>(crit.name == null || c.name ==crit.name) && ...)
为空的搜索条件将给出一个始终为真的子表达式。
获取可查询对象,然后不断向其添加 where 子句。这样您只需要测试一次每个可能的条件,并且只生成绝对需要的 where 子句的数量。
IQueryable<Student> q = dbContext.Students.AsQueryable();
if (crit.name != null)
q = q.Where(c => c.name == crit.name);
if (crit.age != null)
q = q.Where(c => c.age== crit.age);
首先让我说这个答案使用与@PhilWright 的 相同的基本思想。它只是将它包装在一个为您应用此模式的扩展方法中,并允许您拥有一个读起来不错的语法。
public static class SearchExtensions
{
public static IQueryable<Student> Query(this SearchCriteria criteria, IQueryable<Student> studentQuery)
{
return studentQuery
.Match(criteria.name, (student) => student.name == criteria.name)
.Match(criteria.age, (student) => student.age == criteria.age)
.Match(criteria.talent, (student) => student.talent == criteria.talent);
// add expressions for other fields if needed.
}
private static IQueryable<Student> Match<T>(
this IQueryable<Student> studentQuery,
T criterionValue,
Expression<Func<Student, bool>> whereClause) where T : class
{
// only use the expression if the criterion value is non-null.
return criterionValue == null ? studentQuery : studentQuery.Where(whereClause);
}
}
然后您可以像这样在您的代码中使用它:
var criteria = new SearchCriteria() {
name = "Alex",
talent = "Nosepicking"
};
var results = criteria.Query(dbContext.Students);
情况
我有一个接受 POCO 的方法。这个POCO长这样
private class SearchCriteria
{
public string name get;set;
public string age get;set;
public string talent get;set;
..
....
}
该方法主要是对使用上述条件的数据库进行查询。
public void query(SearchCriteria crit)
{
if(crit.name!=null && crit.age!=null && crit.talent !=null)
{
dbContext.Students.Where(c=>c.name ==crit.name && c.age==crit.age...)
}
else if(crit.name !=null && crit.age!=null)
{
}
else if(....
{
}
正如您所看到的,上面有一个明确的问题,在大量条件的情况下,我将不得不编写大量的 if-elses 来从 where 子句中删除特定的参数。
可能的解决方案?
我实际上是 lambda 表达式世界的新手,但我相信我们一定有一个设施可以让我们做如下的事情。
dbContext.Students.Where(processCriteria(searchCriteriaPOCO))
.
你们能指引我正确的方向吗?。谢谢
也许我遗漏了什么,因为代码示例不是我见过的最清晰的,但是对于您的具体示例,我认为以下内容应该没问题:
dbContext.Students.Where(c => (crit.name == null || crit.name == c.name) &&
(crit.age == null || crit.age == c.age) &&
(crit.talent == null || crit.talent == c.talent));
无需链接一堆 if
语句。
对于更复杂的场景,您可能更喜欢 PredicateBuilder
您可以使用这样的模式:
dbContext.Students.Where(c=>(crit.name == null || c.name ==crit.name) && ...)
为空的搜索条件将给出一个始终为真的子表达式。
获取可查询对象,然后不断向其添加 where 子句。这样您只需要测试一次每个可能的条件,并且只生成绝对需要的 where 子句的数量。
IQueryable<Student> q = dbContext.Students.AsQueryable();
if (crit.name != null)
q = q.Where(c => c.name == crit.name);
if (crit.age != null)
q = q.Where(c => c.age== crit.age);
首先让我说这个答案使用与@PhilWright 的
public static class SearchExtensions
{
public static IQueryable<Student> Query(this SearchCriteria criteria, IQueryable<Student> studentQuery)
{
return studentQuery
.Match(criteria.name, (student) => student.name == criteria.name)
.Match(criteria.age, (student) => student.age == criteria.age)
.Match(criteria.talent, (student) => student.talent == criteria.talent);
// add expressions for other fields if needed.
}
private static IQueryable<Student> Match<T>(
this IQueryable<Student> studentQuery,
T criterionValue,
Expression<Func<Student, bool>> whereClause) where T : class
{
// only use the expression if the criterion value is non-null.
return criterionValue == null ? studentQuery : studentQuery.Where(whereClause);
}
}
然后您可以像这样在您的代码中使用它:
var criteria = new SearchCriteria() {
name = "Alex",
talent = "Nosepicking"
};
var results = criteria.Query(dbContext.Students);