2012-03-19 38 views
1

我有一個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,也就是說。

回答

2

我覺得從值類型拳擊是從您的代碼丟失:

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

0

你有沒有試圖改變你的方法定義,包括其他泛型類型,像這樣

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