Построить Any () с деревьями выражений для запросов LINQ - PullRequest
0 голосов
/ 27 мая 2018

Я строю SQL-предложение «Any» динамически, используя класс System.Linq.Expressions.Expression.

Я могу сделать это следующим образом

Expression<Func<User, Lead, bool>> predicate = (user, lead) => user.UserRoleSubProducts.Any(x => x.SubProductID == lead.SubProductID);

Но я не могучтобы добиться этого с помощью дерева выражений.

я пробовал ниже

var param1 = Expression.Parameter(typeof(User), "user");
var property1 = Expression.Property(param1, "UserRoleSubProducts");
var exp1 = Expression.Lambda(property1, new[] { param1 });

var param2 = Expression.Parameter(typeof(Lead), "lead");
var property2 = Expression.Property(param2, "SubProductID");
var exp2 = Expression.Lambda(property2, new[] { param2 });

var param3 = Expression.Parameter(property1.Type.GetProperty("Item").PropertyType, "x");
var property3 = Expression.Property(param3, "SubProductID");
var exp3 = Expression.Lambda(property3, new[] { param3 });

var equality = Expression.Equal(property2, property3);

var any = typeof(Queryable).GetMethods().Where(m => m.Name == "Any").Single(m => m.GetParameters().Length == 2).MakeGenericMethod(property1.Type);

var expression = Expression.Call(null, any, property1, equality);

, но получая

выражение типа 'Microsoft.OData.Client.DataServiceCollection 1[Api.Models.UserRoleSubProduct]' cannot be used for parameter of type System.Linq.IQueryable 1 [Microsoft.OData.Client.DataServiceCollection 1[Api.Models.UserRoleSubProduct]]' of method 'Boolean Any[DataServiceCollection 1] (System.Linq.IQueryable 1[Microsoft.OData.Client.DataServiceCollection 1 [Api.Models.UserRoleSubProduct]], System.Linq.Expressions.Expression 1[System.Func 2 [Microsoft.OData.Client.DataServiceCollection`1 [Api.Models.UserRoleSubProduct], System.Boolean]]) '

Я думаю, что я достаточно близко.Любая помощь приветствуется

1 Ответ

0 голосов
/ 27 мая 2018

Игнорирование избыточных неиспользуемых лямбда-выражений, проблема в последних 2 строках.

Во-первых, вы используете неправильный универсальный тип (MakeGenericMethod(property1.Type)), в то время как правильный тип в основном является типомпараметр x здесь

.Any(x => x.SubProductID == lead.SubProductID)

=>

.Any<T>((T x) => ...)

, который отображается в param3.Type в вашем коде.

Второй, второй аргумент Any должно быть лямбда-выражением (не просто equality, как в коде).

В-третьих, поскольку user.UserRoleSubProducts, скорее всего, является типом коллекции, вы должны отправлять вызов Enumerable.Any, а не Queryable.Any.

Метод Expression.Call имеет перегрузку , что очень удобно для "вызова" статических обобщенных методов расширения:

public static MethodCallExpression Call(
    Type type,
    string methodName,
    Type[] typeArguments,
    params Expression[] arguments
)

Таким образом, последние две строки можно заменить на:

var anyCall = Expression.Call(
    typeof(Enumerable), nameof(Enumerable.Any), new Type[] { param3.Type },
    property1, Expression.Lambda(equality, param3)
);
...