2012-05-25 36 views
5

我試圖動態地重新結構中的一些數據在樹視圖這將允許用戶通過選擇多達三個以下尺寸對數據進行分組,以顯示:創建的GroupBy語句動態

Organisation 
Company 
Site 
Division 
Department 

因此,例如,如果用戶選擇他們想由公司分組然後Site然後分區...下面的代碼將執行所需的分組。

var entities = orgEntities 
// Grouping Level 1 
.GroupBy(o => new { o.CompanyID, o.CompanyName }) 
.Select(grp1 => new TreeViewItem 
     { 
     CompanyID = grp1.Key.CompanyID, 
     DisplayName = grp1.Key.CompanyName, 
     ItemTypeEnum = TreeViewItemType.Company, 
     SubItems = grp1 
       // Grouping Level 2 
       .GroupBy(o => new { o.SiteID, o.SiteName }) 
       .Select(grp2 => new TreeViewItem 
       { 
       SiteID = grp2.Key.SiteID, 
       DisplayName = grp2.Key.SiteName, 
       ItemTypeEnum = TreeViewItemType.Site, 
       SubItems = grp2 
        // Grouping Level 3 
        .GroupBy(o => new { o.Division }) 
        .Select(grp3 => new TreeViewItem 
        { 
         DisplayName = grp3.Key.Division, 
         ItemTypeEnum = TreeViewItemType.Division, 
        }).ToList() 
       }).ToList() 
     }) 
.ToList(); 

這將使這樣的結構法:

+ Company A 
    + Site A 
    + Division 1 
    + Division 2 
    + Site B 
    + Division 1 
+ Company B 
    + Site C 
    + Division 2 
+ Company C 
    + Site D 

然而,這只是爲我提供了在大量的組合的。

我怎麼會去轉換到這個東西,可以動態地創建基於用戶已經選擇了,所以我沒有創建這些表達式每個組合中的一個三維等值表達! ?

謝謝你們。

回答

4

一個有趣的問題。選擇一種類型來分組鍵和另一種類型的結果...使得很有可能得到你要求的東西。

public struct EntityGroupKey 
{ 
    public int ID {get;set;} 
    public string Name {get;set;} 
} 

public class EntityGrouper 
{ 
    public Func<Entity, EntityGroupKey> KeySelector {get;set;} 
    public Func<EntityGroupKey, TreeViewItem> ResultSelector {get;set;} 
    public EntityGrouper NextGrouping {get;set;} //null indicates leaf level 

    public List<TreeViewItem> GetItems(IEnumerable<Entity> source) 
    { 
    var query = 
     from x in source 
     group x by KeySelector(x) into g 
     let subItems = NextGrouping == null ? 
     new List<TreeViewItem>() : 
     NextGrouping.GetItems(g) 
     select new { Item = ResultSelector(g.Key), SubItems = subItems }; 

    List<TreeViewItem> result = new List<TreeViewItem>(); 
    foreach(var queryResult in query) 
    { 
      // wire up the subitems 
     queryResult.Item.SubItems = queryResult.SubItems 
     result.Add(queryResult.Item); 
    } 
    return result; 
    } 

} 

在這種使用方式:

EntityGrouper companyGrouper = new EntityGrouper() 
{ 
    KeySelector = o => new EntityGroupKey() {ID = o.CompanyID, Name = o.CompanyName}, 
    ResultSelector = key => new TreeViewItem 
    { 
    CompanyID = key.ID, 
    DisplayName = key.Name, 
    ItemTypeEnum = TreeViewItemType.Company 
    } 
} 

EntityGrouper divisionGrouper = new EntityGrouper() 
{ 
    KeySelector = o => new EntityGroupKey() {ID = 0, Name = o.Division}, 
    ResultSelector = key => new TreeViewItem 
    { 
    DisplayName = key.Name, 
    ItemTypeEnum = TreeViewItemType.Division 
    } 
} 

companyGrouper.NextGrouping = divisionGrouper; 

List<TreeViewItem> oneWay = companyGrouper.GetItems(source); 

companyGrouper.NextGrouping = null; 
divisionGrouper.NextGrouping = companyGrouper; 

List<TreeViewItem> otherWay = divisionGrouper.GetItems(source); 
+0

另一種方法是使用通用接口IGroupEntities {List GetItems(IEnumerable )}創建5個Grouper類(每種類爲一組),以便它們可以互相調用。 –

+0

感謝您的回答!我曾嘗試過類似的東西,但一定有一個缺失的環節,因爲我從來沒有完成這個迭代。我已經將您的樣本用作初學者,並編寫了一個完全適合我所嘗試的解決方案。非常感謝你!!! – Penfold

+0

+100如果我可以!很好的答案! –

0

另一種選擇是使用DynamicLinq。如果是直LINQ(而不是通過一些DB方面如LINQ2SQL),那麼這可以通過組合您的分組/選擇器字符串來完成:

var entities = orgEntities 
    .GroupBy("new(CompanyID, CompanyName)", "it", null) // DynamicLinq uses 'it' to reference the instance variable in lambdas. 
    .Select(grp1 => new TreeViewItem 
    { 
     ... 
     .GroupBy("new(SiteID, o.SiteName)", "it", null) 
     // And so on... 

你也許可以抽象到每個標準類型的這一點。我看到的唯一問題是內部分組可能不是最容易一起編譯的,但至少這可以讓你開始朝某個方向發展。 DynamicLinq允許您構建動態類型,因此可以進一步抽象它。最終,最大的挑戰是,根據你所分組的內容,生成的TreeViewItem包含不同的信息。動態LINQ的良好用例,但我看到的唯一問題是進一步抽象(到內部分組)。

讓我們知道你想出的,絕對是我以前從來沒有考慮一個有趣的想法。