通过lambdas构造表达式

时间:2015-04-13 05:54:27

标签: c# lambda entity-framework-4

情况

我有一个接受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))

你们能引导我走向正确的方向吗?感谢

4 个答案:

答案 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的搜索条件将给出一个始终为真的子表达式。