使用表达式树为LINQ查询构建Any()函数

4
我将使用System.Linq.Expressions.Expression类动态构建SQL的“Any”子句。
可以按如下方式实现:
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.DataServiceCollection1[Api.Models.UserRoleSubProduct]'的表达式不能用于类型为'System.Linq.IQueryable1[Microsoft.OData.Client.DataServiceCollection1[Api.Models.UserRoleSubProduct]]'的参数。方法为'Boolean Any[DataServiceCollection1](System.Linq.IQueryable1[Microsoft.OData.Client.DataServiceCollection1[Api.Models.UserRoleSubProduct]], System.Linq.Expressions.Expression1[System.Func2[Microsoft.OData.Client.DataServiceCollection`1[Api.Models.UserRoleSubProduct],System.Boolean]])'

我认为我已经接近解决方案了,非常感谢任何帮助。

1个回答

6

忽略冗余未使用的lambda表达式,问题在于最后两行。

首先,您正在使用错误的泛型类型(MakeGenericMethod(property1.Type)),而正确的类型基本上是此处参数x的类型。

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

=>

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

第一,它对应于你的代码中的param3.Type

第二,Any的第二个参数必须是lambda表达式(而不仅仅是代码中的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)
);

非常感谢您的帮助,非常感激。 - Reyan Chougle

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接