Sto costruendo una clausola SQL "Any" usando in modo dinamico la classe System.Linq.Expressions.Expression
Posso farlo in questo modo
Expression<Func<User, Lead, bool>> predicate = (user, lead) => user.UserRoleSubProducts.Any(x => x.SubProductID == lead.SubProductID);
Ma non sono in grado di ottenere questo risultato utilizzando Expression Tree.
Ho provato di seguito
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);
Ma ottenendo
Espressione di tipo "Microsoft.OData.Client.DataServiceCollection
1[Api.Models.UserRoleSubProduct]' cannot be used for parameter of type System.Linq.IQueryable
1 [Microsoft.OData.Client.DataServiceCollection1[Api.Models.UserRoleSubProduct]]' of method 'Boolean Any[DataServiceCollection
1] (System.Linq.IQueryable1[Microsoft.OData.Client.DataServiceCollection
1 [Api.Models.UserRoleSubProduct]], System.Linq.Expressions.Expression1[System.Func
2 [Microsoft .OData.Client.DataServiceCollection`1 [Api.Models.UserRoleSubProduct], System.Boolean]])'
Penso di essere abbastanza vicino. Qualsiasi aiuto è apprezzato
Ignorando le espressioni lambda ridondanti non utilizzate, il problema è nelle ultime 2 righe.
Innanzitutto, stai utilizzando un tipo generico errato ( MakeGenericMethod(property1.Type)
), mentre il tipo corretto è fondamentalmente il tipo del parametro x
qui
.Any(x => x.SubProductID == lead.SubProductID)
=>
.Any<T>((T x) => ...)
che mappa su param3.Type
nel tuo codice.
Secondo, il secondo argomento di Any
deve essere espressione lambda (non semplicemente equality
come nel codice).
In terzo luogo, poiché user.UserRoleSubProducts
molto probabilmente è un tipo di raccolta, è necessario emettere una chiamata a Enumerable.Any
anziché a Queryable.Any
.
Il metodo Expression.Call
ha un sovraccarico che è molto utile per "chiamare" i metodi di estensione generici statici:
public static MethodCallExpression Call(
Type type,
string methodName,
Type[] typeArguments,
params Expression[] arguments
)
Quindi le ultime due righe possono essere sostituite con:
var anyCall = Expression.Call(
typeof(Enumerable), nameof(Enumerable.Any), new Type[] { param3.Type },
property1, Expression.Lambda(equality, param3)
);