使用循环构建Where子句并将每个迭代与OR连接

kie*_*wic 6 c# entity-framework

我有一个 N 对整数的列表,例如:

2, 4
5, 7
9, 10
11, 12
Run Code Online (Sandbox Code Playgroud)

我需要构建一个查询,例如:

WHERE 
    (foo = 2 AND bar = 4) OR
    (foo = 5 AND bar = 7) OR
    (foo = 9 AND bar = 10) OR
    (foo = 11 AND bar = 12)
Run Code Online (Sandbox Code Playgroud)

如果它是一个恒定长度的列表,我可以写如下:

var query = myClass.Where(x =>
    (foo == values[0][0] && bar == values[0][1]) ||
    (foo == values[1][0] && bar == values[1][1]) ||
    (foo == values[2][0] && bar == values[2][1]) ||
    (foo == values[3][0] && bar == values[3][1]));
Run Code Online (Sandbox Code Playgroud)

但列表的长度各不相同,我正在寻找一种使用循环创建查询的方法。

我发现我可以使用Queryable.Union()类似的结果,但考虑到查询中有更多条件,并且对列表可能很长,我宁愿避免union

这个问题有什么解决办法吗?

kie*_*wic 0

我根据使用表达式树的实体框架中的动态查询中描述的类似解决方案找到了此问题的解决方案

这是解决方案。

首先,一个类来保存foobar对:

public class FooBarPair
{
    public int Foo { get; set; }
    public int Bar { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

然后, foosBars的集合:

var pairs = new FooBarPair[]
{
    new Foo() { Foo = 10537, Bar = 1034 },
    new Foo() { Foo = 999, Bar = 999 },
    new Foo() { Foo = 888, Bar = 888 },
    new Foo() { Foo = 10586, Bar = 63 },
};
Run Code Online (Sandbox Code Playgroud)

这是构建查询表达式的代码:

public static void Main()
{
    Expression<Func<MyClass, bool>> whereClause =
        BuildOrExpressionTree<MyClass, int>(pairs, m => m.Foo + m.Bar);

    var myClasss = model.Set<MyClass>();
    IQueryable<MyClass> query = myClasss.Where(whereClause);
}

/// <summary>
/// Starts a recursion to build WHERE (m.Foo = X1 AND m.Bar = Y1) [OR (m.Foo = X2 AND m.Bar = Y2) [...]].
/// </summary>
private static Expression<Func<TValue, bool>> BuildOrExpressionTree<TValue, TCompareAgainst>(
    IEnumerable<FooBarPair> wantedItems,
    Expression<Func<TValue, TCompareAgainst>> convertBetweenTypes1)
{
    ParameterExpression inputParam1 = convertBetweenTypes1.Parameters[0];

    BinaryExpression binaryExpression = convertBetweenTypes1.Body as BinaryExpression;

    Expression binaryExpressionTree = BuildBinaryOrTree<FooBarPair>(
        wantedItems.GetEnumerator(),
        binaryExpression.Left,
        binaryExpression.Right,
        null);

    return Expression.Lambda<Func<TValue, bool>>(binaryExpressionTree, new[] { inputParam1 });
}

/// <summary>
/// Recursive function to append one 'OR (m.Foo = X AND m.Bar = Y)' expression.
/// </summary>
private static Expression BuildBinaryOrTree<T>(
    IEnumerator<FooBarPair> itemEnumerator,
    Expression expressionToCompareTo1,
    Expression expressionToCompareTo2,
    Expression prevExpression)
{
    if (itemEnumerator.MoveNext() == false)
    {
        return prevExpression;
    }

    ConstantExpression fooConstant = Expression.Constant(itemEnumerator.Current.Foo, typeof(int));
    ConstantExpression barConstant = Expression.Constant(itemEnumerator.Current.Bar, typeof(int));

    BinaryExpression fooComparison = Expression.Equal(expressionToCompareTo1, fooConstant);
    BinaryExpression barComparison = Expression.Equal(expressionToCompareTo2, barConstant);

    BinaryExpression newExpression = Expression.AndAlso(fooComparison, barComparison);

    if (prevExpression != null)
    {
        newExpression = Expression.OrElse(prevExpression, newExpression);
    }

    return BuildBinaryOrTree<FooBarPair>(
        itemEnumerator,
        expressionToCompareTo1,
        expressionToCompareTo2,
        newExpression);
}
Run Code Online (Sandbox Code Playgroud)

谢谢大家!