11

コレクションを特定のセットに絞り込むためにさまざまなWhereandステートメントを使用したクエリ可能なものが 1 つあります。WhereBetweenここで、一種の a を追加する必要がありWhere || WhereBetweenます。言い換えれば、今までのようにそれらを連鎖させることはできません。それは And として機能するからです。それで、どうすればこれを行うことができますか?

2 つの可能性があります。

  1. 私が持っているものから2 つのクエリ可能オブジェクトを作成Whereします。1 つは を使用し、もう 1 つは を使用しWhereBetweenます。そして、それらを連結します。これが可能かどうかわかりませんか?また、私の特定のケースではありませんが、おそらく重複してしまうでしょう...
  2. どういうわけか式と で作成された式をある種の Or でマージします。WhereWhereBetween

最初に述べたように、可能かどうかさえわかりません。もしそうなら、それが良い方法であるかどうかはわかりません。

2 つ目は、オプションとして表示できますが、すべての詳細について完全にはわかりません。以下は、WhereBetween私の他の質問からの方法です。これは現在使用しており、うまく機能します。

    public static IQueryable<TSource> WhereBetween<TSource, TValue>(
        this IQueryable<TSource> source,
        Expression<Func<TSource, TValue>> selector,
        IEnumerable<Range<TValue>> ranges)
    {
        var param = Expression.Parameter(typeof(TSource), "x");
        var member = Expression.Invoke(selector, param);
        Expression body = null;
        foreach (var range in ranges)
        {
            var filter = Expression.AndAlso(
                Expression.GreaterThanOrEqual(member,
                     Expression.Constant(range.A, typeof(TValue))),
                Expression.LessThanOrEqual(member,
                     Expression.Constant(range.B, typeof(TValue))));
            body = body == null ? filter : Expression.OrElse(body, filter);
        }
        return body == null ? source : source.Where(
            Expression.Lambda<Func<TSource, bool>>(body, param));
    }

その表現構築部分を新たな手法として抽出できればと考えています。おそらく次のようになります。

    public static IQueryable<TSource> WhereBetween<TSource, TValue>(
        this IQueryable<TSource> source,
        Expression<Func<TSource, TValue>> selector,
        IEnumerable<Range<TValue>> ranges)
    {
        return source.Where(WhereBetween(selector, ranges));
    }

    public static Expression<Func<TSource, bool>> WhereBetween<TSource, TValue>(
        Expression<Func<TSource, TValue>> selector,
        IEnumerable<Range<TValue>> ranges)
    {
        var param = Expression.Parameter(typeof(TSource), "x");
        var member = Expression.Invoke(selector, param);
        Expression body = null;
        foreach (var range in ranges)
        {
            var filter = Expression.AndAlso(
                Expression.GreaterThanOrEqual(member,
                     Expression.Constant(range.A, typeof(TValue))),
                Expression.LessThanOrEqual(member,
                     Expression.Constant(range.B, typeof(TValue))));
            body = body == null ? filter : Expression.OrElse(body, filter);
        }
        return body == null 
            ? ø => true
            : Expression.Lambda<Func<TSource, bool>>(body, param);
    }

次に、その新しいメソッドを使用して、クエリ可能ではなく式を取得できます。WhereBetween(ø => ø.Id, someRange)たとえば、 andがあるとしましょうø => ø.SomeValue == null。これらの 2 つを Or と組み合わせるにはどうすればよいですか? 私はメソッドでExpression.OrElse使用されているを見ていWhereBetweenます.それが私が必要としているものかもしれませんExpression.Or. しかし、私はこの式に関して非常に不安定なので、ここで何を選択すればよいか、または正しい軌道に乗っているかどうかさえわかりません:p

誰かがここで私にいくつかの指針を教えてもらえますか?

4

1 に答える 1

9

Queryable.Unionここには、 、または式の組み合わせの 2 つのオプションがあります。私は一般的に後者OrElseを好みます-これは(少なくともLINQ-to-SQLで)2つの式で実行できます(以下を参照)-しかし、どちらの場合も構成する必要があります:

    using(var ctx = new DataClasses1DataContext())
    {
        ctx.Log = Console.Out;
        Expression<Func<Customer, bool>> lhs =
            x => x.Country == "UK";
        Expression<Func<Customer, bool>> rhs =
            x => x.ContactName.StartsWith("A");

        var arr1 = ctx.Customers.Where(
            lhs.OrElse(rhs)).ToArray();

        var arr2 = ctx.Customers.Where(lhs)
            .Union(ctx.Customers.Where(rhs)).ToArray();
    }

両方ともarr11arr2つのデータベース ヒットのみを実行します (ただし、TSQL は異なります。最初ORWHERE句には があり、2 番目には を含む 2 つの別個のクエリがありUNIONます)。

私が使用した拡張方法は次のとおりです。

static Expression<Func<T, bool>> OrElse<T>(
    this Expression<Func<T, bool>> lhs,
    Expression<Func<T, bool>> rhs)
{
    var row = Expression.Parameter(typeof(T), "row");
    var body = Expression.OrElse(
        Expression.Invoke(lhs, row),
        Expression.Invoke(rhs, row));
    return Expression.Lambda<Func<T, bool>>(body, row);
}
于 2009-02-20T14:25:42.097 に答える