如何创建linq WHERE IN语句而不使用Contains()

本文关键字:Contains 语句 WHERE 何创建 创建 linq IN | 更新日期: 2023-09-27 17:49:55

我有一种情况,我使用的linq提供程序不支持。contains方法在查询中生成where IN子句。我正在寻找一种方法来生成(值= X或值= Y或值= Z)语句动态地从项目列表匹配。我还没有找到一个很好的例子来构建表达式树。

通常我会这样查询:

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

到目前为止,我能找到的最接近的东西是使用动态Linq库,并建立一个字符串来解释,但感觉有点太粗糙了。

如何创建linq WHERE IN语句而不使用Contains()

你甚至不需要一个外部库来做这样的事情:

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"))

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