I have a datatable which i get from the databasemanager class, and i would need to transform that data into a hierarchical structure
either binding it directly to a .net treeview control or in memory first .
i have an ID column, and a ParentID column. what i do not know necessarily is the parent ID to start with. so first thing to do would be to find out which node is the parent ID.
what would be best practice to loop over this table and make it hierarchical
BranchId ParentId ProductCount HasBranchChildren Name
0 NULL 48 1 Categories
1 0 20 1 CategoryA
2 1 10 1 CategoryA1
3 1 8 0 CategoryA2
4 1 2 0 CategoryA3
5 2 4 0 CategoryA1.1
6 2 6 0 CategoryA1.2
7 0 28 1 CategoryB
8 7 20 0 CategoryB1
9 7 8 0 开发者_StackOverflow社区 CategoryB2
this would be an example datatable of course it will have hundreds of items, and it does not always start at the root node, its possible that with a request a certain subset of categories is requested, however i've talked with the database team and they will give me NULL on root nodes in the above example that would be element 0 in the table ....
The root node(s) will/must have the ParentId property null or 0 or some value that tells you that they don't have a parent node. Then you can start to search recursively for the nodes that have the current node id as parent. If all you want to do is display the collection in a tree, there's no need to keep it in memory in a hierarchical structure, you can just go ahead and build the tree. Something like this:
// just a concept, not tested, might have errors
// ObjectWithHierarchy could look something like this
class ObjectWithHierarchy
{
public int Id {get;set;}
public int? ParentId {get;set;}
public string Name {get;set;}
}
private void LoadTree()
{
// initialize your collection of objects
List<ObjectWithHierarchy> list = new List<ObjectWithHierarchy>();
// build the tree
TreeView treeView = new TreeView();
foreach (var item in list.FindAll(i => i.ParentId == null))
{
// create the root node
TreeNode rootNode = new TreeNode();
rootNode.Text = item.Name;
rootNode.Tag = item;
// load child nodes
LoadChildNodes(node, list);
// add the node to the treeview
treeView.Nodes.Add(rootNode);
}
}
private void LoadChildNodes(TreeNode node, List<ObjectWithHierarchy> list)
{
ObjectWithHierarchy item = node.Tag as ObjectWithHierarchy;
foreach (var childItem in list.FindAll(i => i.ParentId == item.Id))
{
// create the child node
TreeNode childNode = new TreeNode();
childNode.Text = childItem.Name;
childNode.Tag = childItem;
// load children, if there are any
LoadChildNodes(childNode, list);
// add it to its parent nodes collection
node.Nodes.Add(childNode);
}
}
There are some third party controls that "know" how to display a hierarchical structure if they know the Id and ParentId properties.
EDIT: just noticed that you're using ASP.NET, and the code is for a winforms treeview, but the concept is roughly the same.
Step 1.
You need to create a tree structure from a table in memory from, this should be simple. Checkout this question here:
Most efficient way of creating tree from adjacency list
Here is some code for your multi root case (I did not want to modify the parent values to some bogus value, therefore the virtual root and its immediate children will have parent = null, but that doe not matter for traversing the tree, since you have Children and IsRoot):
public class Branch
{
public Branch()
{
Children = new List<Branch>();
}
public bool IsRoot { get; set; }
public int? BranchId { get; set; }
public int? ParentId { get; set; }
public List<Branch> Children { get; set; }
public int ProductCount { get; set; }
public int HasBranchChildren { get; set; }
public string Name { get; set; }
//other data
}
public class BranchTreeHelper
{
public Branch MakeTree()
{
var virtualRoot = new Branch()
{
BranchId = null,
ParentId = null,
IsRoot = true
};
// get the data from db, just disregard the properties: Children and IsRoot flage
List<Branch> branchList = GetDataFromDB();
var branchDict = branchList.ToDictionary(i => i.BranchId.Value, i => i);
foreach(var branch in branchList)
{
if(branch.ParentId.HasValue)
{
branchDict[branch.ParentId.Value].Children.Add(branch);
}
else
{
virtualRoot.Children.Add(branch);
}
}
return virtualRoot;
}
}
Step 2.
Sadly MS made it difficult, by not offering a simple generic way to bind to hierarchical data. But luckily others have created code that can. Use this to bind your new tree structure to a tree view:
http://ohds.codeplex.com/
From the project homepage:
ObjectHierarchicalDataSource is to hierarchical data sources what ObjectDataSource is to tabular data sources. It enables the page developer to declaratively bind hierarchical controls such as Menu and TreeView to almost any object graph.
You could create you're own custom implementation of IHierarchicalDataSource but I would strongly advise against that since this is cumbersome and error prone.
Option 2:
If you do not want to use third party user controls the checkout this generic implementation of IHierarchicalDataSource this again can be bound to any hierarchical ASP.NET control:
http://elegantcode.com/2008/04/06/aspnet-hierarchicaldatasourcet/
精彩评论