如何在LINQ中动态添加OR运算符到WHERE子句

时间:2009-04-23 15:44:37

标签: linq linq-to-sql dynamic

我有一个可变大小的字符串数组,我正在尝试以编程方式循环遍历数组并匹配表中的所有行,其中“Tags”列包含数组中的至少一个字符串。这是一些伪代码:

 IQueryable<Songs> allSongMatches = musicDb.Songs; // all rows in the table

我可以轻松地在一组固定的字符串上查询此表过滤,如下所示:

 allSongMatches=allSongMatches.Where(SongsVar => SongsVar.Tags.Contains("foo1") || SongsVar.Tags.Contains("foo2") || SongsVar.Tags.Contains("foo3"));

但是,这不起作用(我得到以下错误:“带有语句体的lambda表达式无法转换为表达式树”)

 allSongMatches = allSongMatches.Where(SongsVar =>
     {
       bool retVal = false;
       foreach(string str in strArray)
       {
         retVal = retVal || SongsVar.Tags.Contains(str);
       }
       return retVal;
     });

有人能告诉我正确的策略吗?我仍然是LINQ世界的新手: - )

4 个答案:

答案 0 :(得分:33)

您可以使用PredicateBuilder类:

var searchPredicate = PredicateBuilder.False<Songs>();

foreach(string str in strArray)
{
   var closureVariable = str; // See the link below for the reason
   searchPredicate = 
     searchPredicate.Or(SongsVar => SongsVar.Tags.Contains(closureVariable));
}

var allSongMatches = db.Songs.Where(searchPredicate);

LinqToSql strange behaviour

答案 1 :(得分:1)

我最近创建了一种扩展方法,用于创建字符串搜索,同时允许进行OR次搜索。关于here

的博文

我还将其创建为可以安装的nuget包:

http://www.nuget.org/packages/NinjaNye.SearchExtensions/

安装完成后,您将可以执行以下操作

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);  
    }  
}

或者,看看NinjaNye.SearchExtensions的github项目,因为这有其他选项,并且已经进行了一些重构以允许其他组合

答案 2 :(得分:0)

自己构建Expression<T>,或者查看其他路线。

假设possibleTags是一个标签集合,您可以使用闭包和连接来查找匹配项。这应该会找到mayTags中至少有一个标签的歌曲:

allSongMatches = allSongMatches.Where(s => (select t from s.Tags
                                            join tt from possibleTags
                                                on t == tt
                                            select t).Count() > 0)

答案 3 :(得分: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的博客here.

找到
相关问题