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

时间:2016-03-09 03:20:50

标签: c# entity-framework

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

2, 4
5, 7
9, 10
11, 12

我需要构建一个类似的查询:

WHERE 
    (foo = 2 AND bar = 4) OR
    (foo = 5 AND bar = 7) OR
    (foo = 9 AND bar = 10) OR
    (foo = 11 AND bar = 12)

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

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

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

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

这个问题有解决办法吗?

5 个答案:

答案 0 :(得分:2)

您可以执行一项操作 - 连接查找字段:barContains,然后使用var filters = new int[][] { new int[] { 2, 4 }, new int[] { 5, 7 }, new int[] { 9, 10 }, new int[] { 11, 12 } }; var newFilter = filters.Select(x => x[0] + "-" + x[1]).ToList(); var answer = dbContext.myClass.Where(x => newFilter.Contains(x.foo + "-" + x.bar)).ToList(); 方法:

    ref.observeEventType(.Value, withBlock: {
        snapshot  in let m = snapshot.value.objectForKey("users/\(self.ref.authData.uid)/email") as? String
        self.EmailLabel.text = m

    })

答案 1 :(得分:1)

假设values是一个锯齿状数组,myClassIEnumerable<T>个具有foobar属性的对象:

var query = myClass.Where(x => values.Any(y => x.foo == y[0] && x.bar == y[1]));

针对Any中每个对象运行的内部myClass语句,查找values中任何内容与foo和{{1}匹配的“行” } bar的属性。本质上,myClass子句迭代表中的每一行,而Any子句迭代(并过滤)Where中的每个对象。

但是,我不知道它会比使用myClass 效率更多。

如评论中所述,此方法不适用于LINQ to Entities。通过从数据库中提取所有记录并在内存中过滤它们,它仍然可以与Entity Framework结合使用,但显然这不是一个有效的解决方案。

答案 2 :(得分:0)

试试这个:

var query = myClass.Where(x => x.Any(p => p[0] == foo && p[1] == bar));

答案 3 :(得分:0)

取整数集并将其制作成地图。然后使用LINQ测试.Any

    var map = new Dictionary<int, int>()
    {
        {2, 4},
        {5, 7},
        {9, 10},
        {11, 12}
    };

    var foo = 2;
    var bar = 4;

    var q = map.Any(kv => foo == kv.Key && bar == kv.Value);

或者,您可以获取int对列表并将它们放入Tuple<int, int>列表中并测试foo和bar,如下所示:

    var q = listOfTuples.Any(tp => foo == tp.Item1 && bar == tp.Item2);

这里的要点是你需要获取“一对一对的列表”并决定如何构建这些信息。一旦你拨打电话,其他一切都将落实到位。一步一步,对吗? :-)

答案 4 :(得分:0)

我根据Dynamic Queries in Entity Framework using Expression Trees

中描述的类似解决方案找到了解决此问题的方法

这是解决方案。

首先,一个持有 foo bar 对的类:

public class FooBarPair
{
    public int Foo { get; set; }
    public int Bar { get; set; }
}

然后, foos 的集合:

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

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

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

谢谢大家!