【问题标题】:Group by Dynamic Aggregate按动态聚合分组
【发布时间】:2018-01-23 13:14:03
【问题描述】:

在下面的代码中,我想将x.BaseSalary 替换为名称存储在feildtoretrive 中的任何其他属性:

var feildtoretrive  = "BaseSalary"
var groupcal = db.Employees.GroupBy(x=>x.Region)
                           .Select(group => new { 
                                    Key = group.Key, 
                                    Avg = group.Average(x => x.BaseSalary) 
                                                })
                           .ToList();

【问题讨论】:

    标签: linq expression-trees


    【解决方案1】:

    你需要

    • 创建一个访问该实例成员的MemberExpression
    • 编译一个 lambda 表达式,为传递的实例参数返回该成员

    (我假设Employees 中的元素是Employee 类型)

    // the parameter expression for the lambda (your 'x')
    var parameter = Expression.Parameter(typeof(Employee));
    // the property access expression (your 'x.BaseSalary' or 'x.<feildtoretrive')
    var propAccess = Expression.PropertyOrField(parameter, feildtoretrive);
    // the build-together and compiled lambda
     var expression = (Expression<Func<Employee, int?>>)Expression.Lambda(propAccess, parameter);
    

    您现在可以使用lambda 来调用x.Average

    new { Key = group.Key, Avg = group.Average(lambda) }
    

    警告:现在这只适用于int? 类型的成员。我缺乏关于如何做到这一点更加独立于类型的经验,但是你可以计算出哪些类型的平均值?但如果有 intdouble 成员,则可能需要另一个演员表。


    编辑:(将返回类型更改为int?)。根据Ivan Stoev's comment我的后续问题,你可以试试这个:

    new { Key = group.Key, Avg = group.AsQueryable().Average(expression) }
    

    EF6 应该识别对AsQueryable() 的调用,然后使用正确的Average 方法(注意我使用expression 作为参数而不是lambda)。 EF Core 和 linq2Sql 不会 使用它。

    【讨论】:

    • 您可以通过使用反射将Expression.Compile 返回的Delegate 转换为基于failedtoretrieve 属性的类型的正确TFunc&lt;Employee,T&gt; 来解决警告。然后,您将反射性地调用 IGrouping.Average,将反射性转换的结果传递到 parameters 对象数组中。
    • 它引发运行时“内部 .NET Framework 数据提供程序错误 102”
    • @user3815413 似乎查询提供程序在将其转换为 sql 时遇到问题。只是为了确定:它“之前”是否有效(仅使用x =&gt; x.BaseSalary)?
    • @user3815413 我编辑了答案,以便更轻松/更短地创建属性访问表达式。它可能解决您的问题,但我认为它可能与属性的类型有关。您测试的属性是decimal 类型吗?
    • @user3815413 唷……不客气,谢天谢地,它起作用了 :) 我终于想明白为什么我的第一个版本没有……
    猜你喜欢
    • 2014-05-29
    • 1970-01-01
    • 1970-01-01
    • 2015-03-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-05-19
    • 2016-04-07
    相关资源
    最近更新 更多