情况
我有一个接受POCO的方法。这个POCO如下所示
private class SearchCriteria
{
public string name get;set;
public string age get;set;
public string talent get;set;
..
....
}
该方法基本上具有对db的查询,该查询使用上述标准。
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))
。
你们能引导我走向正确的方向吗?感谢
答案 0 :(得分:3)
获取可查询,然后继续添加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);
答案 1 :(得分:2)
首先让我说这个答案与@ PhilWright的answer使用相同的基本思想。它只是在一个为你应用这个模式的扩展方法中包含它,并允许你有一个很好的语法。
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);
答案 2 :(得分:1)
也许我错过了一些东西,因为代码示例并不是我见过的最清楚的,但对于您的具体示例,我认为以下情况应该没问题:
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
答案 3 :(得分:0)
你可以使用这样的模式:
dbContext.Students.Where(c=>(crit.name == null || c.name ==crit.name) && ...)
一个为null的搜索条件将给出一个始终为真的子表达式。