使用LINQ对分层数据进行分组

时间:2015-03-31 19:15:02

标签: c# linq entity-framework asp.net-mvc-4

我有一个搜索视图,需要根据组织层次结构中的级别返回所有员工的分组。用户需要能够按此层次结构中的任何级别进行分组。例如,我有下拉检查表,允许为Division,Department,Section,Group选择一个或多个选项。

我在数据模型中表示组织结构的方式如下:

public class OrganizationEntity : IEntity
{

    [DataMember]
    public int Id { get; set; }

    [DataMember]
    public string Name { get; set; }

    [DataMember]
    public int OrganizationEntityTypeId { get; set; }

    [DataMember]
    [ForeignKey("OrganizationEntityTypeId")]
    public virtual OrganizationEntityType OrganizationEntityType { get; set; }

    [DataMember]
    public virtual OrganizationEntity Parent { get; set; }

    public virtual ICollection<OrganizationEntity> Children { get; set; }
}

OrganizationEntityType告诉我组织层次结构中的位置。

员工只链接到一个组织实体,因此员工模型如下:

public class Employee : IEntity
{
    [Key]
    [DataMember]        
    public int Id { get; set; }

    [Required]
    [DataMember]
    public string Name { get; set; }

    [DataMember]
    public int CityId { get; set; }

    [DataMember]
    [ForeignKey("CityId")]
    public virtual City City { get; set; }

    [DataMember]
    public int OrganizationEntityId { get; set; }

    [DataMember]
    [ForeignKey("OrganizationEntityId")]
    public virtual OrganizationEntity OrganizationEntity { get; set; }

}

现在,我正在尝试找出使用LINQ按组织层次结构分组的最佳方法。所以说用户选择Division 1,Division 2,All Sections,Group 1并将他们的分组设置为Divisions,我需要看到数据看起来像这样:

分部员工人数
division1 25
division2 3

如果除了分组以外的相同参数设置为Section,则数据将如下所示:

部门员工人数
第1节15
第2节3
第3节4

等等其他级别。

以下是一个示例数据集:

enter image description here

非常感谢任何建议。

更新

在员工查询中添加了一个过滤器,仅包括组织级别中的那些以及下面的所有组件,现在效果很好!代码如下所示:

var employees = context.Employees.Where(o => orgEntityIds.Contains(o.OrganizationEntityId));

1 个答案:

答案 0 :(得分:2)

LINQ可以使用GroupBy方法执行此操作,但您必须对生成分组键的方式有点创意。这是一个粗略的想法:

Func<Employee, string> selector = (n => FindOrganizationName(n.OrganizationEntity, orgType));
Dictionary<string, int> results = employees.GroupBy(selector)
                                           .ToDictionary(n => n.Key, n => n.Count());

其中FindOrganizationName是一个递归函数,它爬行组织层次结构,直到找到所请求的组织类型,如下所示:

string FindOrganizationName(OrganizationEntity entity, int entityType)
{
    if (entity == null)
    {
        return string.Empty;
    }
    else if (entity.OrganizationEntityTypeId == entityType)
    {
        return entity.Name;
    }
    else
    {
        return FindOrganizationName(entity.Parent, entityType);
    }
}