复杂动态LINQ查询

时间:2013-03-13 00:46:04

标签: c# linq

我正在使用Linq To Entities来启动我的应用程序,我想创建一个非常复杂的搜索查询...看看我想要的是:

  

当用户输入像“华盛顿波士顿”这样的字符串时,我将根据“”(空格,在这种情况下为2个字符串)的数量打破N个字符串并在我的Counties表中搜索华盛顿和波士顿< / p>

如果这是一个“静态”查询,我会这样写:where county.Name.Contains("Washington") || county.Name.Contains("Boston")但我不知道用户将输入多少个城市(或白色空间)...

在经典的纯TSQL环境中,我会在运行时编译查询并使用命令Exec ...所以我的问题是:如何动态生成LINQ to实体查询?

请注意.Where()不是基于委托的扩展方法...它不会在后端转换为TSQL,这意味着from e in context.Counties.Where(c => c.Name.Contains("boston"))会转换为后端的SELECT ID,NAME FROM COUNTIES

3 个答案:

答案 0 :(得分:5)

我只是将David Khaykin的评论扩展为答案,因为这是达到要求的最简单方法。

您只需将搜索字词拆分为字词列表,然后根据您的要求使用counties方法过滤Contains实体

var terms = searchTerm.Split(' ').ToList();

// an exact match  
counties.Where(c => terms.Contains(c.Name))

// a 'contains' or 'like' type match
counties.Where(c => terms.Any(t => c.Contains(t));

Contains方法是System.Linq.Enumerable.Contains,而不是String.Contains

在编写任何复杂的动态LINQ查询时,您可以使用bmused概述的方法 - 非常强大。但是对于这种类型的简单过滤,您可以传递直接列表。

答案 1 :(得分:2)

您可以使用System.Linq.Expressions

所以你会做类似的事情(未经测试):

public Expression<Func<County, Boolean>> GetPredicate(List<String> terms)
{
//The string method - Contains
MethodInfo mContains = typeof(String).GetMethod("Contains");

//The parameter - county
ParameterExpression pe = Expression.Parameter(typeof(County), "County");

//The property - Name
Expression property = Expression.Property(pe, "Name");

//expression body
Expression body = null;

foreach(String term in terms)
{
  //the constant to look for
  Expression searchTerm = Expression.Constant(term);

   //build expression body
   if(body == null) body = Expression.Call(property, mContains, searchTerm);
   else body = Expression.OrElse(body, 
       Expression.Call(property, mContains, searchTerm));
}

//create predicate
return Expression.Lambda<Func<County, Boolean>>(body, pe);
}

答案 2 :(得分:2)

您可以使用Predicate builder(和LINQKit,因为您正在使用实体框架),这样您就可以执行此操作:

IQueryable<County> SearchInCountyNames(params string[] countyNames)
{
  var predicate = PredicateBuilder.False<County>();

  foreach (string countyName in countyNames)
  {
    string name = countyName;
    predicate = predicate.Or(c => c.Name.Contains(name));
  }


  return dataContext.Counties.AsExpandable().Where(predicate);
}

谓词构建器站点上有更多示例。