【问题标题】:Grouping hierarchical data with LINQ使用 LINQ 对分层数据进行分组
【发布时间】:2015-06-05 06:22:23
【问题描述】:

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

在我的数据模型中表示组织结构的方式是这样的:

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,我需要看到数据如下所示:

部门员工人数
师1 25
师2 3

如果将除分组之外的相同参数设置为“部分”,则数据将如下所示:

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

其他关卡以此类推。

这是一个示例数据集:

非常感谢任何建议。

更新

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

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

【问题讨论】:

  • LINQ 在分层数据方面表现不佳。简单的foreach 就可以完成这项工作。或者创建一个包装分层查询的数据库视图(使用 CTE)。

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


【解决方案1】:

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);
    }
}

【讨论】:

  • 这对于顶级分组“Divisions”非常有用,但是当我尝试对任何更低的分组进行分组时出现错误:值不能为空。\r\n参数名称:键
  • 这表明您的列表中有一个Employee 不是您要查找的组织类型的一部分。如果这是设计使然,您应该修改 if (entity == null) portion of FindOrganizationName` 以便它返回一个“真实”字符串而不是 null。然后您可以将该字符串作为键过滤掉结果。
  • 我已经用我正在使用的示例数据更新了我的问题。所有员工都有一个与他们关联的组织实体。
  • 即使所有员工都有一个组织实体关联,他们也可能没有正确的组织类型。例如,如果您基于部门(其中每个部门与一个部门关联)进行搜索,但某些员工直接与一个部门关联,那么这些员工不会与一个部门关联。
  • 更新了我的问题以包含修复我的问题的查询。非常感谢你的帮助!真的很感激:-)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-01-06
相关资源
最近更新 更多