如何在不使用Contains()的情况下创建linq WHERE IN语句

时间:2015-05-20 13:41:52

标签: c# linq contains expression-trees dynamic-linq

我遇到的情况是我使用的linq提供程序不支持.Contains方法在查询中生成WHERE IN子句。我正在寻找一种从要匹配的项目列表动态生成(Value = X OR Value = Y OR Value = Z)语句的方法。我还没有找到构建表达式树的好例子。

通常我会这样查询:

var names = new string[] { "name1", "name2", "name3" }
var matches = query.Where(x => names.Contains(x.Name));

到目前为止,我能找到的最接近的是使用 Dynamic Linq Library并构建一个要解释的字符串,但感觉有点过于hacky。

2 个答案:

答案 0 :(得分:0)

你甚至不需要这样的外部库:

var names = new string[] { "name1", "name2", "name3" };

// Where MyClass is the type of your class
ParameterExpression par = Expression.Parameter(typeof(MyClass));
MemberExpression prop = Expression.Property(par, "Name");

Expression expression = null;

foreach (string name in names)
{
    Expression expression2 = Expression.Equal(prop, Expression.Constant(name));

    if (expression == null)
    {
        expression = expression2;
    }
    else
    {
        expression = Expression.OrElse(expression, expression2);
    }
}

var query = ...; // Your query

if (expression != null)
{
    // Where MyClass is the type of your class
    var lambda = Expression.Lambda<Func<MyClass, bool>>(expression, par);
    query = query.Where(lambda);
}

您可以使用属性Expression.OrElse与其中一个Name之间的比较来构建string的连接。

在这种特殊情况下(3 string s),从调试器查看时得到的Expression是:

(((Param_0.Name == "name1") OrElse (Param_0.Name == "name2")) OrElse (Param_0.Name == "name3"))

答案 1 :(得分:0)

只是通过xanatos改进答案:

var names = new string[] { "name1", "name2", "name3" };

var query = ...; // Your query

if (names.Any())
{
    // Where MyClass is the type of your class
    ParameterExpression par = Expression.Parameter(typeof(MyClass));
    MemberExpression prop = Expression.Property(par, "Name");

    var expression=names
        .Select(v => Expression.Equal(prop, Expression.Constant(v)))
        .Aggregate(Expression.OrElse);

    // Where MyClass is the type of your class
    var lambda = Expression.Lambda<Func<MyClass, bool>>(expression, par);
    query = query.Where(lambda);
}