按动态聚合分组

Group by Dynamic Aggregate

在下面的代码中,我想将 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();

你需要

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

(我假设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 成员,则可能需要另一个强制转换表达式。


编辑:(将 return 类型更改为 int?)。根据 关于我的后续问题,你可以试试这个:

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

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