0

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

当用户输入像“Washington Boston”这样的字符串时,我将根据“”(空格,在本例中为 2 个字符串)的数量将其分成 N 个字符串,然后在我的 Counties 表中搜索华盛顿和波士顿

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

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

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

4

3 回答 3

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 概述的方法 - 非常强大。但是对于这种类型的简单过滤,您可以传递直接列表。

于 2013-03-13T01:58:43.960 回答
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);
}
于 2013-03-13T01:37:43.433 回答
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);
}

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

于 2013-03-13T01:39:57.443 回答