【问题标题】:Group By Multiple Columns dynamically按多列动态分组
【发布时间】:2014-07-23 09:35:42
【问题描述】:

有什么方法可以动态分组多列吗?

例如。 group x by new { x.Column1, x.Column2 }

x.Column1 等我想动态设置(从 UI)

【问题讨论】:

  • 检查this post
  • 谢谢,上面的帖子显示了两种方式。第一个使用常规 LINQ 的方法似乎无法正常工作,而且似乎太难看,无法解决这样一个基本问题。第二个使用动态 LINQ 的方法可能是这样。有没有其他简单的方法来解决这个简单的挑战?
  • 我不知道,要么构建表达式树,要么使用动态 linq。
  • 这就是问题所在,如何为“group by new {}”语法构建表达式树?

标签: entity-framework linq-to-sql group-by


【解决方案1】:

在 db 站点上动态实现这一点的方法非常复杂,因为我们无法动态创建匿名类型。要替换它们,我建议创建一个类:

public class CustomTuple<T1, T2>
{
    public T1 Item1 { get; set; }
    public T2 Item2 { get; set; }
}

我们不能在这里使用元组,因为它没有默认构造函数。在 CustomTuple 类中,最多放置尽可能多的参数 T 和尽可能多的属性。如果您将在该类中定义 5 个属性,但对于查询,您将只使用 3 个,您只需将 3 个属性设置为适当的值,其余 2 个属性保持为空 - 查询仍然有效。或者,您可以在运行时使用 CodeDOM 动态生成适当的类。然后是查询逻辑:

Type[] parameterTypes = new Type[] { typeof(int), typeof(object) };
Type tupleType = typeof(CustomTuple<,>).MakeGenericType(parameterTypes);
ParameterExpression x = Expression.Parameter(typeof(Entity));
NewExpression body = Expression.New(tupleType.GetConstructor(new Type[0]), new Expression[0]);
MemberBinding binding1 = Expression.Bind(
    typeof(CustomTuple<,>).MakeGenericType(parameterTypes).GetProperty("Item1"),
    Expression.Property(x, "Value"));
MemberInitExpression memberInitExpression =
    Expression.MemberInit(
        body,
        binding1);

Expression<Func<Entity, object>> exp = Expression.Lambda<Func<Entity, object>>(memberInitExpression, x);
using (MyDbContext context = new MyDbContext())
{
    var list = context.Entities.GroupBy(exp).ToList();
}

以上代码按值属性对实体进行分组。 parameterTypes 可以在程序执行期间动态构建 - 这是用于 group by 中的键选择的匿名类型的属性类型列表。基于此,我们创建了适当的 CustomTuple 类型。然后我们在运行时动态创建 binding1 元素 - 每个属性一个,为分组键设置。在上面的示例中,我只创建了一个。通过使用 NewExpression 和 MemberBinding 表达式,我们可以使用 MemberInit 方法构建初始化表达式。最后,您从中构建 lambda 表达式并针对 db 执行它。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-10-25
    • 2015-12-02
    • 2017-02-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多