【问题标题】:Dynamic GroupBy using expression in .net core动态 GroupBy 在 .net core 中使用表达式
【发布时间】:2017-04-13 09:56:27
【问题描述】:

我写了一个扩展方法,根据条件做一个表达式,但是当条件是groupby时,结果是order by!!! 我怎么了?

这是我的方法:

  public static IQueryable<T> NewWhere<T, U>(this IQueryable<T> source, string prop, U value, string condition)
  {
  MethodInfo method;
  Expression<Func<T, bool>> lambda = null;
  Expression body = null;

  string groupSelector = null;
  var type = typeof(T);
  var parameter = Expression.Parameter(type, "p");
  var property = Expression.Property(parameter, prop);
  var constant = Expression.Constant(value, typeof(U));


  if (condition == "GreaterThan")
  body = Expression.GreaterThan(property, constant);
  else if (condition == "LessThan")
  body = Expression.LessThan(property, constant);
  else if (condition == "Equals")
  body = Expression.Equal(property, constant);

  //For implement sql like command we need them
  else if (condition == "StartsWith") {
  method = typeof(string).GetMethod("StartsWith", new[] { typeof(string) });
  body = Expression.Call(property, method, constant);
  }
  else if (condition == "EndsWith")
  {
  method = typeof(string).GetMethod("EndsWith", new[] { typeof(string) });
  body = Expression.Call(property, method, constant);
  }
  else if (condition == "Contains")
  {
  method = typeof(string).GetMethod("Contains", new[] { typeof(string) });
  body = Expression.Call(property, method, constant);
  }
  //For implement sql like command we need them

  //group by only one field
  if (condition == "GroupBy")
  groupSelector = prop;

  else
  lambda = Expression.Lambda<Func<T, bool>>(body, new[] { parameter });

  //return the grouped by result or not grouped by
  if (groupSelector != null)
  {
  var selectorExp = Expression.Lambda<Func<T, U>>(property, new ParameterExpression[] { parameter });
  source = source.GroupBy(selectorExp).SelectMany(g => g);
  //source.GroupBy(e => e.GetType().GetProperty(groupSelector)).SelectMany(gr => gr);
  }
  else
  source = source.Where(lambda);

  return source;
  }

但是当我使用 GroupBy 条件运行方法时,结果是:

SELECT [e].[Id], [e].[Year]
FROM [org].[Data] AS [e]
ORDER BY [e].[Year]

我不知道为什么会这样?

【问题讨论】:

    标签: c# entity-framework linq extension-methods


    【解决方案1】:

    TL;DR;:Entity Framework 使用查询,因为它是获得所需内容的最有效方式。

    Entity Framework 所做的是将您的 LINQ 查询转换为 SQL。检查这行代码:

    source = source.GroupBy(selectorExp).SelectMany(g => g);
    

    您正在分组(可能按年份),然后选择该组的所有项目。您实际上并没有请求分组结果集,而是希望所有组中的所有项目在单个平面结果集中。如果 EF 会先请求组,然后再请求组项,则它首先必须选择所有组:

    SELECT [e].[Year]
    FROM [org].[Data] AS [e]
    GROUP BY [e].[Year]
    

    然后它必须在一个查询中获取组项对于每个组

    SELECT [e].[Id]
    FROM [org].[Data] AS [e]
    WHERE [e].[Year] = --Value
    

    这当然会非常低效(特别是因为您无论如何都使用SelectMany 展平列表),因此 EF 只会获取按您的分组谓词排序的值并在查询执行期间对它们进行分组(或者在这种情况下不分组它们完全没有,因为您正在请求一个平面列表)。一旦执行了查询,EF就可以从结果集的顶部开始,每次遇到新的一年就开始一个新的组。

    当您使用 EF 查询时,您必须接受您无法控制 SQL。如果需要,请创建存储过程并从 EF 运行它们。

    【讨论】:

    • 我遇到了这个错误,是因为我使用了 selectMany:无法将类型 'System.Linq.IQueryable' 隐式转换为 'System.Linq.IQueryable',我应该选择分组。 selectMany 可以将所有数据组合在一起是吗?
    • 您的方法的返回类型与您的GroupBy 语句的返回类型不匹配。您必须相应地更改方法的返回类型。不过,这很可能不会改变您的 SQL 输出。
    • 如何更改 groupby 的返回类型,因为我无法更改方法的返回类型,返回的 T,U 类型是我从 groupby 之前的属性制作的 lambda 表达式
    • 你不能改变GroupBy的返回类型。这就是SelectMany 的用途。在这种情况下,您必须使用您所拥有的。
    猜你喜欢
    • 1970-01-01
    • 2021-08-30
    • 2021-03-12
    • 1970-01-01
    • 1970-01-01
    • 2020-02-02
    • 1970-01-01
    • 2021-07-30
    • 1970-01-01
    相关资源
    最近更新 更多