动态GroupBy在.net核心中使用表达式

时间:2016-11-29 11:54:47

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

我编写了一个基于条件创建表达式的扩展方法,但是当条件为groupby时,结果是按顺序排序! 我错了什么?

这是我的方法:

  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条件运行mthod时,结果是:

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

我不知道为什么会这样?

1 个答案:

答案 0 :(得分:2)

TL; DR; :Entitity 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运行它们。