【问题标题】:Build Any() with Expression Trees for LINQ Queries使用 LINQ 查询的表达式树构建 Any()
【发布时间】:2018-05-27 10:12:54
【问题描述】:

我正在使用 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]' cannot be used for parameter of type System.Linq.IQueryable1[Microsoft.OData.Client.DataServiceCollection1[Api.Models.UserRoleSubProduct]]' of method '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]])'

我想我已经足够接近了。任何帮助表示赞赏

【问题讨论】:

    标签: c# linq expression-trees


    【解决方案1】:

    忽略多余的未使用的 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 方法具有 overload,这对于“调用”静态泛型扩展方法非常方便:

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

    【讨论】:

    • 非常感谢。非常感谢您的帮助
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多