如何在LINQ中向WHERE子句动态添加OR运算符
我有一个大小可变的字符串数组,我正试图通过编程在数组中循环并匹配表中的所有行,其中列“Tags”至少包含数组中的一个字符串。下面是一些伪代码:如何在LINQ中向WHERE子句动态添加OR运算符,linq,linq-to-sql,dynamic,Linq,Linq To Sql,Dynamic,我有一个大小可变的字符串数组,我正试图通过编程在数组中循环并匹配表中的所有行,其中列“Tags”至少包含数组中的一个字符串。下面是一些伪代码: IQueryable<Songs> allSongMatches = musicDb.Songs; // all rows in the table 但是,这不起作用(我得到以下错误:“带有语句体的lambda表达式无法转换为表达式树”) 有人能告诉我实现这一目标的正确策略吗?我对LINQ:-)的世界还是新手。你可以使用这个类: var
IQueryable<Songs> allSongMatches = musicDb.Songs; // all rows in the table
但是,这不起作用(我得到以下错误:“带有语句体的lambda表达式无法转换为表达式树”)
有人能告诉我实现这一目标的正确策略吗?我对LINQ:-)的世界还是新手。你可以使用这个类:
var searchPredicate=PredicateBuilder.False();
foreach(strArray中的字符串str)
{
var closureviable=str;//有关原因,请参见下面的链接
搜索谓词=
searchPredicate.Or(SongsVar=>SongsVar.Tags.Contains(closurevaluate));
}
var allSongMatches=db.Songs.Where(searchPredicate);
要么自己构建一个
表达式
,要么看另一条路线
假设possibleTags是标记的集合,您可以使用闭包和联接来查找匹配项。这将在可能的标签中找到至少有一个标签的任何歌曲:
allSongMatches = allSongMatches.Where(s => (select t from s.Tags
join tt from possibleTags
on t == tt
select t).Count() > 0)
还有另一种更简单的方法可以实现这一点。ScottGu的博客详细介绍了一个动态linq库,我过去发现它非常有用。从本质上讲,它根据传入的字符串生成查询。下面是您要编写的代码示例:
Dim Northwind As New NorthwindDataContext
Dim query = Northwind.Products _
.Where("CategoryID=2 AND UnitPrice>3") _
.OrderBy("SupplierId")
Gridview1.DataSource = query
Gridview1.DataBind()
更多信息可以在scottgu的博客上找到我最近创建了一个扩展方法,用于创建字符串搜索,该方法还允许
或
搜索。写博客
我还将其创建为一个nuget软件包,您可以安装:
一旦安装,您将能够执行以下操作
var result = db.Songs.Search(s => s.Tags, strArray);
如果要创建自己的版本以允许上述操作,则需要执行以下操作:
public static class QueryableExtensions
{
public static IQueryable<T> Search<T>(this IQueryable<T> source, Expression<Func<T, string>> stringProperty, params string[] searchTerms)
{
if (!searchTerms.Any())
{
return source;
}
Expression orExpression = null;
foreach (var searchTerm in searchTerms)
{
//Create expression to represent x.[property].Contains(searchTerm)
var searchTermExpression = Expression.Constant(searchTerm);
var containsExpression = BuildContainsExpression(stringProperty, searchTermExpression);
orExpression = BuildOrExpression(orExpression, containsExpression);
}
var completeExpression = Expression.Lambda<Func<T, bool>>(orExpression, stringProperty.Parameters);
return source.Where(completeExpression);
}
private static Expression BuildOrExpression(Expression existingExpression, Expression expressionToAdd)
{
if (existingExpression == null)
{
return expressionToAdd;
}
//Build 'OR' expression for each property
return Expression.OrElse(existingExpression, expressionToAdd);
}
}
公共静态类QueryableExtensions
{
公共静态IQueryable搜索(此IQueryable源、表达式stringProperty、参数string[]searchTerms)
{
如果(!searchTerms.Any())
{
返回源;
}
表达式orExpression=null;
foreach(searchTerms中的var searchTerm)
{
//创建表达式以表示x.[property]。包含(searchTerm)
var searchTermExpression=Expression.Constant(searchTerm);
var containsExpression=BuildContainsExpression(stringProperty,searchTermExpression);
orExpression=BuildOrExpression(orExpression,containsExpression);
}
var completeExpression=Expression.Lambda(orExpression,stringProperty.Parameters);
返回source.Where(completeExpression);
}
私有静态表达式BuildOrExpression(表达式existingExpression、表达式expressionToAdd)
{
if(existingExpression==null)
{
返回要添加的表达式;
}
//为每个属性生成“或”表达式
返回表达式.OrElse(existingExpression,expressionToAdd);
}
}
或者,看一看github项目,因为它有其他选项,并且已经进行了一些重构,以允许其他组合谢谢Mehrdad,您的解决方案以创纪录的速度出现,效果非常好!我不知道PredicateBuilder类。多方便的功能啊!我也很感激你对使用临时变量来保存字符串的评论……这会让我发疯的!VictorI对创建var searchPredicate的假表达式感到困惑,这需要假吗?或者其他合适的东西?(谈论PredicateBuilder.False())它必须是False,因为构造的查询需要看起来像“False | | |包含x | | |包含y | |…”“嘿,Richard,感谢您的反馈。由于某些原因,VS不喜欢您建议的代码语法…我是否遗漏了一些明显的内容?很可能是有错误。。。需要一点时间来整理数据/测试线束以进行确认。但在内部理解表达式中添加了select子句。。。这是必需的(oops)。
Dim Northwind As New NorthwindDataContext
Dim query = Northwind.Products _
.Where("CategoryID=2 AND UnitPrice>3") _
.OrderBy("SupplierId")
Gridview1.DataSource = query
Gridview1.DataBind()
var result = db.Songs.Search(s => s.Tags, strArray);
public static class QueryableExtensions
{
public static IQueryable<T> Search<T>(this IQueryable<T> source, Expression<Func<T, string>> stringProperty, params string[] searchTerms)
{
if (!searchTerms.Any())
{
return source;
}
Expression orExpression = null;
foreach (var searchTerm in searchTerms)
{
//Create expression to represent x.[property].Contains(searchTerm)
var searchTermExpression = Expression.Constant(searchTerm);
var containsExpression = BuildContainsExpression(stringProperty, searchTermExpression);
orExpression = BuildOrExpression(orExpression, containsExpression);
}
var completeExpression = Expression.Lambda<Func<T, bool>>(orExpression, stringProperty.Parameters);
return source.Where(completeExpression);
}
private static Expression BuildOrExpression(Expression existingExpression, Expression expressionToAdd)
{
if (existingExpression == null)
{
return expressionToAdd;
}
//Build 'OR' expression for each property
return Expression.OrElse(existingExpression, expressionToAdd);
}
}