使用Linq或Entity在`.Where`之间的`或`

时间:2014-10-26 07:30:24

标签: c# linq entity-framework

我有一个使用linq从Words表搜索的函数。我想.split(' ')输入单词并搜索每个单词。但我希望or在我的条件之间而不是and。请参阅生成的SQL代码。

public static List<Word> GetWords(string word_Fa, string word_En)
{
    var db = Global.GetEntitiy();

    var query = from item in db.Words
                select item;

    foreach (var item in word_Fa.Split(' '))
    {
        query = query.Where(a => a.Word_Fa.Contains(item));
    }

    foreach (var item in word_En.Split(' '))
    {
        query = query.Where(a => a.Word_En.Contains(item));
    }

    return query.ToList();
}

生成的SQL代码:

SELECT [t0].[ID], [t0].[UserID], [t0].[Word_En], [t0].[Word_Fa], [t0].[UpVotes], [t0].[DownVotes], [t0].[DateTime], [t0].[Status]
FROM [Words] AS [t0]
WHERE ([t0].[Word_En] LIKE @p0) AND ([t0].[Word_En] LIKE @p1) AND ([t0].[Word_Fa] LIKE @p2) AND ([t0].[Word_Fa] LIKE @p3)

4 个答案:

答案 0 :(得分:2)

您可以考虑使用来自Here的谓词构建器,正如@Hadi Hassan在评论中所说的那样。 通过使用它,您的代码将是这样的:

var predicate = PredicateBuilder.False<Words>();

var query = from item in Words
            select item;

var FaWords = "A B C".Split(' ');
var EnWords = "D E F".Split(' ');

foreach (string item in FaWords)
{
    predicate = predicate.Or(p => p.Word_Fa.Contains(item));
}

foreach (string item in EnWords)
{
    predicate = predicate.Or(p => p.Word_En.Contains(item));
}

return query.Where(predicate).toList();

并且sql查询将是:

SELECT [t0].[ID], [t0].[UserID], [t0].[Word_En], [t0].[Word_Fa], [t0].[UpVotes], [t0].
[DownVotes], [t0].[DateTime], [t0].[Status]
FROM [Words] AS [t0]
WHERE ([t0].[Word_Fa] LIKE @p0) OR ([t0].[Word_Fa] LIKE @p1) OR ([t0].[Word_Fa] LIKE @p2) OR ([t0].[Word_En] LIKE @p3) OR ([t0].[Word_En] LIKE @p4) OR ([t0].[Word_En] LIKE @p5)

顺便说一下,如果你遇到这个错误:LINQ to Entities不支持LINQ表达式节点类型'Invoke'。

您应该将LinqKit nuget包添加到项目中,并将返回行更改为:

return query.AsExpandable().Where(predicate).toList();
祝你好运

答案 1 :(得分:2)

不使用LinqKit的解决方案:

扩展类与PredicateBuilder非常相似,但它可以与linq一起使用实体,而linq可以直接使用sql:

public static class PredicateHelper
{
    public static Expression<Func<T, bool>> True<T>() { return f => true; }
    public static Expression<Func<T, bool>> False<T>() { return f => false; }

    public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> expr1,
                                                        Expression<Func<T, bool>> expr2)
    {
        if (expr1 == null)
        {
            throw new ArgumentNullException("expr1");
        }
        if (expr2 == null)
        {
            throw new ArgumentNullException("expr2");
        }
        var visitor = new ParameterUpdateVisitor(expr2.Parameters.First(), expr1.Parameters.First());
        expr2 = visitor.Visit(expr2) as Expression<Func<T, bool>>;
        return Expression.Lambda<Func<T, bool>>
              (Expression.OrElse(expr1.Body, expr2.Body), expr1.Parameters);
    }

    public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> expr1,
                                                         Expression<Func<T, bool>> expr2)
    {
        if (expr1==null)
        {
            throw new ArgumentNullException("expr1");
        }
        if (expr2 == null)
        {
            throw new ArgumentNullException("expr2");
        }
        var visitor = new ParameterUpdateVisitor(expr2.Parameters.First(), expr1.Parameters.First());
        expr2 = visitor.Visit(expr2) as Expression<Func<T, bool>>;
        return Expression.Lambda<Func<T, bool>>
              (Expression.AndAlso(expr1.Body, expr2.Body), expr1.Parameters);
    }

    class ParameterUpdateVisitor : ExpressionVisitor
    {
        private readonly ParameterExpression _oldParameter;
        private readonly ParameterExpression _newParameter;

        public ParameterUpdateVisitor(ParameterExpression oldParameter, ParameterExpression newParameter)
        {
            _oldParameter = oldParameter;
            _newParameter = newParameter;
        }

        protected override Expression VisitParameter(ParameterExpression node)
        {
            if (ReferenceEquals(node, _oldParameter))
                return _newParameter;

            return base.VisitParameter(node);
        }
    }
}

使用绝对等于PredicateBuilder:

var predicate = PredicateBuilder.False<Words>();

var query = from item in Words
            select item;

var FaWords = "A B C".Split(' ');
var EnWords = "D E F".Split(' ');

foreach (string item in FaWords)
{
    var item1 = item;
    predicate = predicate.Or(p => p.Word_Fa.Contains(item1));
}

foreach (string item in EnWords)
{
    var item1 = item;
    predicate = predicate.Or(p => p.Word_En.Contains(item1));
}

return query.Where(predicate).toList();

答案 2 :(得分:0)

除非我遗漏了什么,否则我觉得这对你有用:

public static List<Word> GetWords(string word_Fa, string word_En)
{
    var db = Global.GetEntitiy();
    return db.Words
                .Where(w => w.Word_Fa.Intersect(word_Fa.Split(' ')).Any() ||
                            w.Word_En.Intersect(word_En.Split(' ')).Any())
                .ToList();
}

答案 3 :(得分:-1)

您想要word_Faqueryword_Fa.Split(' ')中的每个项目检查query。因此,将它们加入到该字符串中,它将为word_Fa.Split(' ')中的所有项目提供var query1 = (from q in query join item in word_Fa.Split(' ') on q.Word_Fa equals item select q).ToList(); var query2 = (from q in query join item in word_En.Split(' ') on q.Word_En equals item select q).ToList(); return query1.Union(query2); 中的所有项目:

{{1}}