Вызов метода расширения .Any с Entity Framework с использованием деревьев выражений - PullRequest
2 голосов
/ 28 декабря 2010

Я посмотрел несколько примеров здесь Вызов метода из выражения и MSDN , но я не смог получить правильный вызов метода / тип объекта для Any ()для запроса ниже.Кажется, я могу получить вызов свойства, но не IEnumerable часть дочернего свойства.
billing_map_set_lu является родителем billmaps_lu и определяется как ассоциация в Entity Framework.

Причина, по которой я использую деревья выражений, заключается в том, что мне нужно иметь возможность определять запрос во время выполнения с помощью предложений 1-n .SelectMany (p => p.billmaps_lu) .Where (предикат).Поэтому я подумал, что если бы я мог построить деревья выражений, я бы справился со всеми различными комбинациями, которые у меня есть для этой системы, которых много.

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

Я пробовал довольно много попыток, используя примеры выше ...

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

Приведенная выше часть выглядит хорошо, но когда я пытаюсь сделать. Любой Это похоже наЯ не могу получить правильное свойство / метод, чтобы получить правильные объекты.(Я чувствую, что у меня физическая проблема, когда я работаю с неправильными модулями.) Я надеюсь, что это что-то простое, что мне не хватает, я довольно плохо знаком с деревьями выражений ... Я включил нерабочий код, чтобы попробоватьчтобы показать вам, где моя голова и как кто-то может направить меня в правильном направлении.

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)

1 Ответ

0 голосов
/ 20 мая 2011

Отказ от ответственности, у меня нет скомпилированного рабочего кода.

2 проблемы.

Первая проблема, вероятно, заключается в:

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

Это не тот параметр, который вам нужен:

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

Измените billMapSetParameter на billMaps ParamterExpression, тогда вам будет хорошо идти.Вы вызываете PropertyExpression, чтобы получить свой billMapSet для вас из ParameterExpression.

2-я проблема: (Не уверен, но мое внутреннее чувство) Вам может потребоваться передать выражение Where как ConstantExpression с типом Expression <.Func<>>..Any метод принимает два параметра, из которых вторым является Expression <.Func <>> (или просто Func <>? Не помню).

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

Затем передаем обратно в исходное состояние.где вы «myWhereClause1».

Перекрестный палец, это работает

Редактировать - Удалите это, ПОКАЗАТЬ 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();
    }
}
...