IQueryable.GroupBy覆盖抛出int和布尔值,但不是字符串

问题描述:

我有一个IQueryable的扩展方法的第一个草案与GroupBy应该由命名属性分组的覆盖。IQueryable.GroupBy覆盖抛出int和布尔值,但不是字符串

在问你之前,我没有使用动态表达式API(又名动态Linq),因为我无法弄清楚如何通过它访问每个组的计数。该库中的GroupBy方法返回一个非通用的IQueryable,而不是我需要的一个IQueryable<IGrouping<>>。如果有办法通过图书馆了解统计数字,我会很乐意接受一个答案,告诉我如何。也许某种语法,我找不到string elementSelector参数中的文档?

代码:

public static IQueryable<IGrouping<object, T>> GroupBy<T>(this IQueryable<T> source, string propertyName) 
    { 
     ParameterExpression param = Expression.Parameter(typeof(T), String.Empty); 
     MemberExpression property = Expression.PropertyOrField(param, propertyName); 
     LambdaExpression group = Expression.Lambda(property, param); 

     MethodCallExpression call = Expression.Call(
      typeof(Queryable), 
      "GroupBy", 
      new[] { typeof(T), property.Type }, 
      source.Expression, 
      Expression.Quote(group)); 

     return source.Provider.CreateQuery<IGrouping<object, T>>(call); 
    } 

我使用它是这样的:

public IEnumerable<Category> GetCategories(IQueryable<T> entities, string property) 
    { 
     var haba = entities.GroupBy(property); 
     var categories = haba.Select(group => new Category(group.Key.ToString(), group.Count())); 
     return categories.ToArray(); 
    } 

而且只要我的属性是字符串类型的它workes罚款。但是,如果我试图把它用在一个int或布尔财产,我得到类似如下的错误在电话会议中的createQuery:

参数表达的类型为 System.Linq.IQueryable 1[System.Linq.IGrouping 2 System.Int32, DerivedEntity1]] 当类型 System.Collections.Generic.IEnumerable 1[System.Linq.IGrouping 2 [System.Object,DerivedEntity1]] 预计。参数名:表达

我注意到,它的预期的IEnumerable通用的,而不是一个IQueryable,这很奇怪。但是一个很好的提示。您无法将IEnumerable投射到IQueryable而不执行AsQueryable()。那么问题是,为什么它给我一个IEnumerable而不是IQueryable?为什么当我传递一个字符串属性的propertyName时,它不会以相同的方式失败?

我应该提一下,我的IQueryable的实例是来自NHibernate的NhQueryable,也就是说。

我觉得从值类型拳击是从您的代码丢失:

public static IQueryable<IGrouping<object, T>> GroupBy<T>(this IQueryable<T> source, string propertyName) 
{ 
    ParameterExpression param = Expression.Parameter(typeof(T), String.Empty); 
    MemberExpression property = Expression.PropertyOrField(param, propertyName); 
    UnaryExpression convert = Expression.Convert(property, typeof(object)); 
    LambdaExpression group = Expression.Lambda(convert, param); 

    MethodCallExpression call = Expression.Call(
     typeof(Queryable), 
     "GroupBy", 
     new[] { typeof(T), typeof(object) }, 
     source.Expression, 
     Expression.Quote(group)); 

    return source.Provider.CreateQuery<IGrouping<object, T>>(call); 
} 
+0

这就像一个魅力。非常感谢你! :) – Mithon 2012-03-20 08:20:12

+0

相当有用的感谢 – 2017-09-29 13:07:51

你有没有试图改变你的方法定义,包括其他泛型类型,像这样

public static IQueryable<IGrouping<O, T>> GroupBy<O, T>(this IQueryable<T> source, string propertyName) 
{  
    return source.Provider.CreateQuery<IGrouping<O, T>>(call); 

} 

消耗它像:

var haba = entities.GroupBy<int, Category>(property); 
+0

不起作用,因为我将不得不在运行时通过T上的反射来推测O类型ertyName。泛型需要在编译时确定。除非我错过了什么..? – Mithon 2012-03-19 18:06:46

+0

@Mithon - 你不需要在运行时做任何事情。您正在编译时指定类型。 * entities.GroupBy (property)* – Aducci 2012-03-19 18:12:24

+0

no .. cause有时propertyName将对应于O = string类型的属性,有时O = int,有时O = DateTime等等等等。关于我发送的一个字符串,它传递给一个传递名为propertyName的字符串的web服务。 – Mithon 2012-03-19 21:42:27