Aufrufen der .Any-Erweiterungsmethode mit Entity Framework mithilfe von Ausdrucksstrukturen

c# entity-framework expression-trees

Frage

Ich habe hier ein paar Beispiele für das Aufrufen einer Methode aus einem Ausdruck und auf MSDN angeschaut, aber ich konnte nicht den richtigen Methodenaufruf / Objekttyp für Any () für die folgende Abfrage abrufen. Es scheint mir möglich zu sein, den Aufruf der Eigenschaft, aber nicht IEnumerable Teil der untergeordneten Eigenschaft zu erhalten.
billing_map_set_lu ist das übergeordnete Element von billmaps_lu und ist im Entity Framework als Assoziation definiert.

Der Grund, warum ich Ausdrucksbäume verwende, ist, dass ich in der Lage sein muss, die Abfrage zur Laufzeit mit 1-n. SelectMany (p => p.billmaps_lu) .Where (Prädikat) -Klauseln zu definieren. Also dachte ich, wenn ich die Ausdrucksbäume bauen könnte, könnte ich mit all den verschiedenen Kombinationen umgehen, die ich für dieses System habe, die viele sind.

var myResults = ctx.billing_map_set_lu
                   .Where(p => p.billmaps_lu.Any(b => b.billmap_columnname == "templatesittings_key" &&  b.billmap_columnvalue == 428264))
                                   SelectMany(p => p.billmaps_lu)
                   .Where (b =>b.billmap_columnname =="locations_key" && b.billmap_columnvalue == 12445)
                                   Select(z => z.billing_map_set_lu);

Ich habe ein paar Versuche mit den obigen Beispielen versucht ...

ParameterExpression bms = Expression.Parameter(typeof(billmaps_lu));
Expression left1 = Expression.Property(bms, typeof(billmaps_lu).GetProperty("billmap_columnname"));
Expression right1 = Expression.Constant("templatesittings_key", typeof(string));
Expression InsideAny1 = Expression.Equal(left1, right1);
Expression left2 = Expression.Property(bms, typeof(billmaps_lu).GetProperty("billmap_columnvalue"));
Expression right2 = Expression.Constant(428264, typeof(int));
Expression InsideAny2 = Expression.Equal(left2, right2);
Expression myWhereClause1 = Expression.AndAlso(InsideAny1, InsideAny2);

Der obige Teil scheint in Ordnung, aber wenn ich versuche, die .Any Es ist wie ich kann nicht die richtige Eigenschaft / Methode, um die richtigen Objekte heraus zu bekommen. (Ich habe das Gefühl, dass ich ein physikalisches Problem habe, wo ich mit den falschen Einheiten arbeite.) Ich hoffe, dass es etwas Einfaches ist, dass ich vermisse. Ich bin ziemlich neu bei Expression Trees. Ich habe nicht funktionierenden Code zum Testen hinzugefügt um dir zu zeigen, wo mein Kopf ist und wie mich jemand in die richtige Richtung lenken kann.

MethodInfo method = typeof(Enumerable).GetMethods().Where(m => m.Name == "Any" && m.GetParameters().Length == 2).Single().MakeGenericMethod(typeof(billing_map_set_lu).GetProperty("billmaps_lu").PropertyType);
ParameterExpression billMapSetParameter = Expression.Parameter(typeof(billing_map_set_lu), "p");
ParameterExpression billMaps = Expression.Parameter(typeof(billmaps_lu), "p1");
var myFunction = Expression.Lambda<Func<billmaps_lu, bool>>(Expression.Call(method, Expression.Property(billMapSetParameter, typeof(billing_map_set_lu).GetProperty("billmaps_lu")), myWhereClause1), billMaps)

Akzeptierte Antwort

Haftungsausschluss, ich habe keinen kompilierten Arbeitscode.

2 Probleme.

Das erste Problem liegt wahrscheinlich in:

ParameterExpression billMapSetParameter = Expression.Parameter(typeof(billing_map_set_lu), "p");

Das ist kein Parameter, den du brauchst:

Expression.Lambda<Func<billmaps_lu, bool>>(Expression.Call(method, Expression.Property(**billMapSetParameter**, typeof(billing_map_set_lu).GetProperty("billmaps_lu")), myWhereClause1), billMaps)

Ändern Sie den billMapSetParameter in den billMaps ParamterExpression, dann sollten Sie gut gehen. Sie rufen den PropertyExpression auf, um Ihr billMapSet für Sie von ParameterExpression abzurufen.

2. Problem: (Nicht sicher, aber mein Bauchgefühl) Möglicherweise müssen Sie die Where-Klausel als ConstantExpression mit dem Ausdruck <.Func <>> übergeben. .Jede Methode benötigt zwei Parameter, von denen der zweite ein Ausdruck <.Func <>> ist (oder nur ein Func <>? Kann sich nicht erinnern).

var whereExpression = Expression.Lambda<.Func<.billmaps_lu, bool>>(myWhereClause1, bms);
var ce = Expression.Constant(whereExpression)

Dann gib ce wieder in original wo du "myWhereClause1" ist.

Crossfinger funktioniert

Bearbeiten- Schrott, SHOW MI ZEH CODEZ

public class Foo
{
    public List<string> Strings { get; set; }
}

class Program
{
    static void Main(string[] args)
    {
        Func<Foo, bool> func =
            a => a.Strings.Any(b => b == "asdf");

        // b => b == "asdf";
        var bParameter = Expression.Parameter(typeof (string));
        var asdfConstant = Expression.Constant("asdf");
        var compare = Expression.Equal(bParameter, asdfConstant);
        var compareExpression = Expression.Lambda<Func<string, bool>>(compare, bParameter);
        var ceCompareExpression = Expression.Constant(compareExpression.Compile());

        // a => a.Strings.Any(compareExpression)
        var parameter = Expression.Parameter(typeof (Foo));

        var foosProperty = Expression.Property(parameter, typeof (Foo).GetProperty("Strings"));
        MethodInfo method = typeof(Enumerable).GetMethods().Where(m => m.Name == "Any" && m.GetParameters().Length == 2).Single().MakeGenericMethod(typeof(string));

        var anyMethod = Expression.Call(method, foosProperty, ceCompareExpression);

        var lambdaExpression = Expression.Lambda<Func<Foo, bool>>(anyMethod, parameter);

        // Test.
        var foo = new Foo {Strings = new List<string> {"asdf", "fdsas"}};

        Console.WriteLine(string.Format("original func result: {0}", func(foo)));
        Console.Write(string.Format("constructed func result: {0}", lambdaExpression.Compile()(foo)));

        Console.ReadKey();
    }
}



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