【问题标题】:Construct expression for where through lambdas通过 lambda 构造 where 的表达式
【发布时间】:2015-04-13 19:01:44
【问题描述】:

情况

我有一个接收 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-else 来从 where 子句中删除特定的参数。

可能的解决方案?

我实际上是 lambda 表达式世界的新手,但我相信我们必须有一个工具可以让我们执行以下操作。

dbContext.Students.Where(processCriteria(searchCriteriaPOCO)).

你们能把我引向正确的方向吗?谢谢

【问题讨论】:

  • 如果任何答案充分解决了您的问题,请您选择它作为答案,或者如果您自己找到更好的方法,请将其作为答案发布。跨度>

标签: c# lambda entity-framework-4


【解决方案1】:

获取一个可查询的,然后继续向其中添加 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);

【讨论】:

  • Nit:我要么使用var,要么放弃.AsQueryable()。如果您明确指定类型,则后者没有任何值。
  • 您的权利。我是从头顶上做的。
  • Phil ,如果连续的 IF 被执行,它不会替换 "q" 中的值吗? .这样只有最后一个 where 子句在“q”中。还是所有成功的 if 都会累积各自的 where 子句?
  • @MuhammadAhmedAbuTalib q.Where(...) 返回一个包含 where 子句表达式的新 IQueryable&lt;Student&gt; 实例。您可以链接 where 表达式。
  • Alex 所以这意味着如果上面代码 sn-p 中的两个 if 都为真,我们将对数据库进行两次查询,对吗? .所以如果我们有十个 ifs,将与 DB 服务器来回走动,十次?
【解决方案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);

【讨论】:

  • 这真是天才和整洁。
  • 我真的很羡慕你的才华:D。
【解决方案3】:

也许我遗漏了一些东西,因为代码示例不是我见过的最清晰的,但是对于您的具体示例,我认为以下应该没问题:

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

【讨论】:

    【解决方案4】:

    你可以使用这样的模式:

    dbContext.Students.Where(c=>(crit.name == null || c.name ==crit.name) && ...)
    

    为空的搜索条件将给出一个始终为真的子表达式。

    【讨论】:

      猜你喜欢
      • 2023-03-31
      • 1970-01-01
      • 2015-09-06
      • 1970-01-01
      • 2015-12-23
      • 1970-01-01
      • 1970-01-01
      • 2013-05-24
      • 1970-01-01
      相关资源
      最近更新 更多