C #, Linq2Sql: Ist es möglich, zwei Abfragetabellen zu einem zusammenzufassen?

c# expression-trees iqueryable lambda linq-to-sql

Frage

Ich habe einen abfragbaren wo ich verwendet habe verschiedene Where und zwischen WhereBetween Aussagen über die Sammlung zu verengen , um einen bestimmten Satz. Jetzt muss ich eine Art Where || WhereBetween hinzufügen Where || WhereBetween . Mit anderen Worten, ich kann sie nicht einfach so aneinander ketten, wie ich es bisher getan habe, denn das wird wie ein Und funktionieren. Also, wie kann ich das tun?

Ich sehe zwei Möglichkeiten:

  1. Erstellen Sie zwei Abfrageabfragen von dem einen, das ich habe, eins, das Where , und eins, das WhereBetween . Und dann verketten Sie sie . Weiß nicht, ob das überhaupt möglich ist? Auch, wenn auch nicht in meinem speziellen Fall, würden Sie höchstwahrscheinlich mit Duplikaten enden ...
  2. Irgendwie verschmelzen der Where Ausdruck und der im WhereBetween erzeugte Ausdruck mit einer Art Or.

Der erste, wie gesagt, ich bin mir nicht sicher, ist sogar möglich. Und wenn es war, bin ich mir nicht sicher, ob es ein guter Weg ist, es zu tun.

Die zweite kann ich als eine Option sehen, aber nicht ganz sicher über alle Details. Unten ist die WhereBetween Methode von meiner anderen Frage, die ich jetzt benutze und es funktioniert 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));
    }

Ich denke, dass ich den Ausdruck, der Teil davon ist, vielleicht in eine neue Methode extrahieren könnte. Vielleicht so:

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

Ich könnte dann diese neue Methode verwenden, um den Ausdruck anstelle des abfragbaren zu erhalten. Also, sagen wir, ich habe das WhereBetween(ø => ø.Id, someRange) und zum Beispiel ø => ø.SomeValue == null . Wie kann ich diese beiden mit Oder kombinieren? Ich schaue mir die Expression.OrElse die in der WhereBetween Methode verwendet wird, und ich denke, das könnte das sein, was ich brauche, oder vielleicht ist das die Expression.Or . Aber ich bin sehr instabil in diesem Ausdruck, also bin ich mir nicht sicher, was ich hier wählen soll oder ob ich auf dem richtigen Weg bin: p

Könnte mir jemand hier ein paar Hinweise geben?

Akzeptierte Antwort

Sie haben hier zwei Optionen - Queryable.Union oder Ausdruckskombination. Letzteres OrElse ich über OrElse - was (zumindest mit LINQ-to-SQL) mit 2 Ausdrücken möglich ist (siehe unten) - aber in jedem Fall sollte es sich zusammensetzen:

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

Sowohl arr1 als auch arr2 jeweils nur einen Datenbanktreffer aus (obwohl der TSQL anders ist; der erste hat ein OR in der WHERE Klausel; der zweite hat zwei getrennte Abfragen mit UNION ).

Hier ist die Erweiterungsmethode, die ich verwendet habe:

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



Lizenziert unter: CC-BY-SA with attribution
Nicht verbunden mit Stack Overflow
Ist diese KB legal? Ja, lerne warum
Lizenziert unter: CC-BY-SA with attribution
Nicht verbunden mit Stack Overflow
Ist diese KB legal? Ja, lerne warum