Appel de la méthode d'extension .Any avec Entity Framework à l'aide d'arbres d'expression

c# entity-framework expression-trees

Question

J'ai examiné quelques exemples ici. Appel d'une méthode à partir d'une expression et sur MSDN, mais je n'ai pas été en mesure d'obtenir le bon type appel / objet de méthode pour Any () pour la requête ci-dessous. Il semble que je puisse obtenir l'appel de propriété mais pas une partie de la propriété enfant.
billing_map_set_lu est le parent de billmaps_lu et est défini comme une association dans Entity Framework.

J'utilise des arbres d'expression parce que je dois pouvoir définir la requête au moment de l'exécution avec les clauses 1-n. SelectMany (p => p.billmaps_lu) .Where (prédicat). J'ai donc pensé que si je pouvais construire les arbres d'expression, je pourrais gérer toutes les combinaisons que j'ai pour ce système, qui sont nombreuses.

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

J'ai essayé plusieurs fois en utilisant les exemples ci-dessus ...

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 partie ci-dessus semble bien, mais lorsque j'essaie de faire le .Tout c'est comme si je ne pouvais pas obtenir la bonne propriété / méthode pour obtenir les bons objets. (Je sens que je suis sur un problème de physique où je travaille avec les mauvaises unités.) J'espère que c'est quelque chose de simple qui me manque, je suis assez nouveau dans Expression Trees. pour vous montrer où en est ma tête et comment on peut me guider dans la bonne direction.

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)

Réponse acceptée

Déni de responsabilité, je n'ai pas de code de travail compilé.

2 problèmes.

Le premier problème réside probablement dans:

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

Ce n'est pas un paramètre dont vous avez besoin dans:

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

Remplacez billMapSetParameter par billMaps ParamterExpression, alors vous devriez être prêt à partir. Vous appelez la PropertyExpression pour obtenir votre billMapSet à partir de la ParameterExpression.

2ème problème: (Pas sûr, mais mon instinct est grand) Vous devrez peut-être passer la clause Where en tant que ConstantExpression de type Expression <.Func <>>. Toute méthode prend deux paramètres, dont le second est une expression <.Func <>> (ou simplement un Func <>? Impossible de se souvenir).

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

Puis reparlez ce à l'origine où vous êtes "myWhereClause1".

Croisé ça marche

Edit- Scrap that, MONTRER 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();
    }
}


Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow