Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/sql-server-2008/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在LINQ中向WHERE子句动态添加OR运算符_Linq_Linq To Sql_Dynamic - Fatal编程技术网

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

如何在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

我有一个大小可变的字符串数组,我正试图通过编程在数组中循环并匹配表中的所有行,其中列“Tags”至少包含数组中的一个字符串。下面是一些伪代码:

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