Chiamare il metodo .Any Extension con Entity Framework usando Expression Trees

c# entity-framework expression-trees

Domanda

Ho visto alcuni esempi qui Chiamando un metodo da un'espressione e su MSDN, ma non sono stato in grado di ottenere il giusto tipo di chiamata / tipo di oggetto per Any () per la query riportata di seguito. Mi sembra di essere in grado di ottenere la chiamata di proprietà ma non IEnumerable parte della proprietà figlio.
billing_map_set_lu è il genitore di billmaps_lu ed è definito come un'associazione in Entity Framework.

La ragione per cui sto usando gli alberi di espressioni è che devo essere in grado di definire la query in fase di esecuzione con clausole 1-n .SelectMany (p => p.billmaps_lu) .Where (predicato). Così ho pensato che se potessi costruire gli alberi di espressione potrei gestire tutte le diverse combinazioni che ho per questo sistema che sono molte.

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

Ho provato un bel paio di tentativi utilizzando gli esempi sopra ...

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

La parte sopra sembra buona, ma quando provo a fare il. Any è come se non riuscissi a ottenere il giusto metodo / proprietà per ottenere gli oggetti giusti. (Mi sento come se fossi su un problema di fisica dove sto lavorando con le unità sbagliate.) Spero che sia qualcosa di semplice che mi manca, sono abbastanza nuovo per Expression Trees .. Ho incluso codice non funzionante per provare per mostrarti dove è la mia testa e come qualcuno può guidarmi nella giusta direzione.

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)

Risposta accettata

Disclaimer, non ho alcun codice di lavoro compilato.

2 problemi.

Il primo problema risiede probabilmente in:

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

Questo non è un parametro di cui hai bisogno in:

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

Cambia billMapSetParameter in ParameterExpression di billMaps, quindi dovresti essere pronto. Stai chiamando PropertyExpression per ottenere il tuo billMapSet per te da ParameterExpression.

2 ° problema: (Non sono sicuro, ma ho la sensazione di sentirsi bene) Potrebbe essere necessario passare la clausola Where come espressione costante con tipo Expression <.Func <>>. . Ogni metodo prende due parametri, di cui, il secondo è un'espressione <.Func <>> (o solo un Func <>? Non può ricordare).

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

Quindi passa indietro in origine dove si trova "myWhereClause1".

Incrocio funziona

Modifica: elimina ciò, MOSTRA 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();
    }
}


Autorizzato sotto: CC-BY-SA with attribution
Non affiliato con Stack Overflow
È legale questo KB? Sì, impara il perché
Autorizzato sotto: CC-BY-SA with attribution
Non affiliato con Stack Overflow
È legale questo KB? Sì, impara il perché