I have some flat data coming from the database that looks like this:
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"}
};
I would like to convert it to this:
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
}
}
}
};
which will ultimately display like this in a treeview:
+Admin (Group)
John Doe (User)
Jane Smith (User)
+Support (Group)
Johnny Support (User)
+SubSupport (Group)
Sub Johnny Support (User)
+Production (Group)
Johnny Production (User)
This is what I've come up with so far to transform the flat data into the model above:
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);
}
}
All my groups come out along with their children users but the hierarchy is not preserved. I think I may need to do this recursively but I can't seem to get my head around it. Any help would be greatly appreciated.
Here are the models for the sake of completeness:
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; }
}
I'd do this in 3 passes:
Create all
Group
classes and populate them with data other than child groups, adding them incrementally to a dictionary mapping ID to Group.Loop through all the groups in the dictionary and add children to their parents'
Groups
list of children.Return a filtered list of all groups with no parent group -- these are the root groups. (I also sorted them by ID to remove the random ordering that the dictionary will introduce.)
Thus:
I also modified your
Group
class a little to automatically allocate the lists: