平面数据到层次模型C#

时间:2014-11-15 18:50:51

标签: c# tree group-by hierarchy flat

我有一些来自数据库的平面数据,如下所示:

List<FlatDataGroup> elements = new List<FlatDataGroup>()
        {
            new FlatDataGroup {Text = "", GroupID = 1, ParentGroupID = 0, GroupName = "Admin", UserID = 1, UserName = "John Doe"},
            new FlatDataGroup {Text = "", GroupID = 1, ParentGroupID = 0, GroupName = "Admin", UserID = 2, UserName = "Jane Smith"},
            new FlatDataGroup {Text = "", GroupID = 2, ParentGroupID = 1, GroupName = "Support", UserID = 3, UserName = "Johnny Support"},
            new FlatDataGroup {Text = "", GroupID = 3, ParentGroupID = 2, GroupName = "SubSupport", UserID = 4, UserName = "Sub Johnny Support"},
            new FlatDataGroup {Text = "", GroupID = 4, ParentGroupID = 1, GroupName = "Production", UserID = 5, UserName = "Johnny Production"}
        };

我想将其转换为:

List<Group> model = new List<Group>
            {
                new Group()
                {
                    ID = 1,
                    Name = "Admin",
                    ParentGroupID = 0,
                    Type = "Group",
                    Users = new List<User>()
                    {
                        new User()
                        {
                            ID = 1,
                            Name = "John Doe",
                            GroupID = 1,
                            Type = "User",
                        },
                        new User()
                        {
                            ID = 2,
                            Name = "Jane Smith",
                            GroupID = 1,
                            Type = "User",
                        },
                    },
                    Groups = new List<Group>
                    {
                        new Group()
                        {
                            ID = 2,
                            Name = "Support",
                            ParentGroupID = 1,
                            Type = "Group",
                            Users = new List<User>()
                            {
                                new User()
                                {
                                    ID = 3,
                                    Name = "Johnny Support",
                                    GroupID = 2,
                                    Type = "User",
                                }
                            },
                            Groups = new List<Group>()
                            {
                                new Group()
                                {
                                    ID = 3,
                                    Name = "SubSupport",
                                    ParentGroupID = 2,
                                    Type = "Group",
                                    Users = new List<User>()
                                    {
                                        new User()
                                        {
                                            ID = 4,
                                            Name = "Sub Johnny Support",
                                            GroupID = 3,
                                            Type = "User",
                                        }
                                    },
                                    Groups = null
                                }
                            }
                        },
                        new Group()
                        {
                            ID = 4,
                            Name = "Production",
                            ParentGroupID = 1,
                            Type = "Group",
                            Users = new List<User>()
                            {
                                new User()
                                {
                                    ID = 5,
                                    Name = "Johnny Production",
                                    GroupID = 4,
                                    Type = "User",
                                }
                            },
                            Groups = null
                        }
                    }
                }
            };

最终将在树视图中显示如下:

+ Admin(Group)
John Doe(用户)
简史密斯(用户)
+支持(组)
约翰尼支持(用户)
+ SubSupport(Group)
Sub Johnny支持(用户)
+生产(集团)
约翰尼制作(用户)

到目前为止,我已经提出将平面数据转换为上述模型:

List<Group> model = new List<Group>();

        var parentGrouping = elements.GroupBy(x => x.ParentGroupID);

        foreach (var parentGroup in parentGrouping)
        {
            var grouping = parentGroup.GroupBy(y => y.GroupID);

            foreach (var group in grouping)
            {
                Group groupItem = new Group()
                {
                    ID = group.FirstOrDefault().GroupID,
                    Name = group.FirstOrDefault().GroupName,
                    ParentGroupID = group.FirstOrDefault().ParentGroupID,
                    Type = "Group",
                    Users = new List<User>()
                };

                foreach (var user in group)
                {
                    groupItem.Users.Add(new User()
                        {
                            ID = user.UserID,
                            Name = user.UserName,
                            GroupID = user.GroupID,
                            Type = "User",
                        });
                }

                model.Add(groupItem);
            }
        }

我的所有小组都与他们的子级用户一起出现,但不保留层次结构。我想我可能需要递归地做这件事,但我似乎无法理解它。任何帮助将不胜感激。

为了完整起见,以下是模型:

public class FlatDataGroup
{
    public string Text { get; set; }
    public int GroupID { get; set; }
    public int ParentGroupID { get; set; }
    public string GroupName { get; set; }
    public int UserID { get; set; }
    public string UserName { get; set; }
}

public class Group
{
    public int ID { get; set; }
    public int ParentGroupID { get; set; }
    public string Name { get; set; }
    public List<Group> Groups { get; set; }
    public List<User> Users { get; set; }
    public string Type { get; set; }
}

public class User
{
    public int ID { get; set; }
    public int GroupID { get; set; }
    public string Name { get; set; }
    public string Type { get; set; }
 }

1 个答案:

答案 0 :(得分:1)

我在3次通过中做到了这一点:

  1. 创建所有Group类,并使用除子组之外的数据填充它们,将它们逐步添加到字典映射ID到组。

  2. 遍历字典中的所有组并将子项添加到其父项中。 Groups孩子名单。

  3. 返回没有父组的所有组的筛选列表 - 这些是根组。 (我还按ID对它们进行排序,以删除字典将引入的随机排序。)

  4. 因此:

    public static class FlatDataGroupExtensions
    {
        public const string UserType = "User";
        public const string GroupType = "Group";
    
        public static List<Group> ToGroups(this IEnumerable<FlatDataGroup> elements)
        {
            // Allocate all groups and index by ID.
            var groups = new Dictionary<int, Group>();
            foreach (var element in elements)
            {
                Group group;
                if (!groups.TryGetValue(element.GroupID, out group))
                    groups[element.GroupID] = (group = new Group() { ID = element.GroupID, Name = element.GroupName, ParentGroupID = element.ParentGroupID, Type = GroupType });
                group.Users.Add(new User() { GroupID = element.GroupID, ID = element.UserID, Name = element.UserName, Type = UserType });
            }
            // Attach child groups to their parents.
            foreach (var group in groups.Values)
            {
                Group parent;
                if (groups.TryGetValue(group.ParentGroupID, out parent) && parent != group) // Second check for safety.
                    parent.Groups.Add(group);
            }
            // Return only root groups, sorted by ID.
            return groups.Values.Where(g => !groups.ContainsKey(g.ParentGroupID)).OrderBy(g => g.ID).ToList();
        }
    }
    

    我还修改了你的Group课程以自动分配列表:

    public class Group
    {
        List<Group> groups = new List<Group>();
        List<User> users = new List<User>();
    
        public int ID { get; set; }
        public int ParentGroupID { get; set; }
        public string Name { get; set; }
        public string Type { get; set; }
        public List<Group> Groups { get { return groups; } }
        public List<User> Users { get { return users; } }
    
        public override string ToString()
        {
            return string.Format("Group: ID={0}, Name={1}, Parent ID={2}, #Users={3}, #Groups={4}", ID, Name, ParentGroupID, Users.Count, Groups.Count);
        }
    }