Who Is This Article For?

This article is aimed at .NET developers who need to build a tree (or forest) of objects by loading an array or list of rows from a database, and converting them to a tree structure in memory to use or display.

Introduction

Storing hierarchical data in a database is a very common requirement, whether it be product categories, sports tournaments, or staff hierarchies. Over the years, I have had to create, store in a database and display trees many times, and my method has evolved from having fixed-size hierarchies, to abstract classes providing tree functionality, and finally to the method described in this article. This article describes a very simple way to load data from a table, and convert it into a tree in C# code for .NET 2.0+.

While other articles have been written on the subject, the following goals are not always met:

You should not need to extend an abstract class, because your data class may already extend another class

You shouldn't need to convert your class to be a partial class

You shouldn't need to change your database table: as long as it uses the standard parent ID column referring to its own primary key, it should work

There shouldn't need to be any type-casting of parent or child objects

It should be easy to use

The answer is to define an interface - in this case called ITreeNode<t /> - and then have a utility method to build a tree from that. This article assumes that you have a class defined to hold a single node (e.g. a Category object), and that when you get a list of nodes from the database each reference to a parent has been instantiated as an object with its ID set, but without a reference to the fully populated parent object, nor its children.

An Example

Let's look at the very common "Category" entity, used to categorise products. The database table looks like the following:

Let's assume that there are just 8 rows in the database, which break the products into two main categories - "Hardware" and "Software" - and then further sub-categories. In this case "Operating Systems" and "Developer Tools" come under "Software"; "Monitors" and "Peripherals" under "Hardware", and finally "Keyboards" and "Mice" under "Peripherals", giving the following category hierarchy:

In the database, the rows are as follows:

In order to display this information on a website, you create a "Category" class:

A method is also needed to retrieve all the categories from the database. This will be a "flat" list of each category, i.e. the _parent field will point to an object which only has its ID populated, and _children will be null. A possible example of this method is shown here:

If the current category was "Keyboards", this would render the following HTML:

/ Hardware / Peripherals / Keyboards

Tree Helper

The TreeHelper utility class contains numerous other useful methods - such as GetDepth and HasHierarchyLoop - and iterators - such as DepthFirstTraversal, BreadthFirstTraversal, ClimbToRoot, FromRootToNode, and Siblings.

Check out the fully-documented source code for the full details.

Using Extension Methods and "LINQ to Trees"

If you are using a .NET 3.5 solution, you are able to take advantage of extension methods. This has the effect of implementing methods in interface declarations (which is not possible in older versions of C#), which is probably the most useful aspect of extension methods, and indeed was the reason they were invented.

Remember, ConvertToForest, FindCategory, DepthFirstTraversal and GetDepth are not implemented by the Category class, it simply "inherits" these methods from the TreeHelper class, simply by implementing ITreeNode<T>.

Extension methods go hand-in-hand with LINQ. Yes, strictly speaking, this is simply "LINQ to Objects" rather than "LINQ to trees", but regardless, it is a new way to query your trees:

List<Category> categoryList = Category.GetCategories();
// Get all categories which are not top level categories,
// and retrieve only the name.
var nonRootCategories =
from c in categoryList.DepthFirstTraversalOfList()
where c.Parent != nullselectnew { Name = c.Name };
// Get all categories at Depth 2, ordered by name, and
// get the whole category object.
var level2Categories =
from c in categoryList.DepthFirstTraversalOfList()
where c.GetDepth() == 2orderby c.Name ascendingselect c;

Some Cool Stuff

The following .NET language features have made this class much more useful:

Interfaces using Generic parameters. Note that the interface definition is ITreeNode<T>, and the reference to the parent, for example, is T Parent. This means you never need to cast from ITreeNode to your class.

Creating iterators using the "yield" keyword. This is perhaps one of the more under-rated features introduced in .NET 2.0 which makes creating Iterators so easy. Check out the methods in the TreeHelper<T>.Iterators class.

Extension methods and LINQ. Querying trees with LINQ can certainly make certain tasks much easier... and fun.

History

27th February, 2008: Initial release

2nd March 2008: Changed TreeHelper from a generic class to non-generic class with generic methods (to allow type method inference), and added the section on LINQ.

I have one control called TreeView1 on the page and want to add rootNodes and ChildNodes. Can you please guide how to populate treeview with parent and child items. Actually want to know where to place the code to fill Root Nodes and where to put the code for ChildNodes..I am getting index error on rootNode.ChildNodes.Add(childNode) line..Please guide by correcting my code.

Your classes are great and exactly what I needed. I am novice in asp.net world so need your help.

I've followed your instructions step by step and did the following.

1. Created a database and Category table in SQLSERVER 2008.2. Created a stored procedure to retrieve all nodes3. Downloaded and Add your class "ITreeNodeDotNet3.cs" in my solution.4. Created a class file "Category.cs"

Problems I am facing------------------------1. Even though I've build the Category.cs but still its showing red underline in "Default.aspx.cs" where I called "(Category.GetListFromDatabase());" it cant find GetListFromDatabase()..

2. I dont know how to do where you said Once having a list of objects in memory, the ITreeNode interface comes in handy. The first step is to implement this interface:

publicclass Category : ITreeNode<Category> {
// contents of class remain as above, because the
// interface is implemented by the Id, Parent, and
// Children properties
}

I've added the interface code right after Category class but its not working..

I am having problems correcting "ITreeNodeDotNet3.cs" even though followed "okoji cyril" but didnt get him correctly I guess..

Here is my code of "ITreeNodeDotNet3.cs".

using System;
using System.Collections.Generic;
namespace TreeUtility
{
///<summary>/// An object which implements this interface is considered a node in a tree.
///</summary>publicinterface ITreeNode<T>
where T : class
{
///<summary>/// A unique identifier for the node.
///</summary>int Id
{
get;
}
///<summary>/// The parent of this node, or null if it is the root of the tree.
///</summary> T Parent
{
get;
set;
}
///<summary>/// The children of this node, or an empty list if this is a leaf.
///</summary>///public System.Collections.Generic.IList<Category> Children
{
get { return _children; }
set { _children = value; }
}
//IList<T> Children
//{
// get { return _child; }
// set;
// }
}

On compilation its throwing an error "modifier 'public' is not valid for this item d:\dynamicmenu\App_Code\ITreeNodeDotNet3.cs Line 34 Column 59

Line 34 is----------public System.Collections.Generic.IList&lt;Category&gt; Children

I think this is the last problem and after that I will have the implementation of your lovely Tree object.

That defines the interface and so can't have any implementation (things like return _children; is implementation). The problem okiji pointed out is that the interface (ITreeNode<T>) didn't match the implementation (Category). So, you should still have the following in the ITreeNodeDotNet3 file:

IList<T> Children
{
get;
set;
}

Hope that helps. Once you get it working, you will understand a lot more if you learn about interfaces in C# and also learn about generics. I'm sure there will be lots of good articles here on CodeProject. Good luck!

I found your article very useful for creating a famil tree in XMAL (3.5) and managed to prodcue a WPF control that binds to a db table.

However, your code throws an eception when a child with the same name are entered under under more than parent. I need to produce a tree view like the one below; but as your code defines a unique ID for each node, it seems it woud not be possible to build this kind of tree.

For a problem like this, you would need to declare separate classes for students and teams (which makes sense; you can't say a student is a type of cricket team). Make individual Team objects (All Students, Class A, etc), where each team has a list of students, and each student has a list of teams (in the database, there would be a many-to-many relationship with a StudentTeam table or similar).

In fact, you may not need to use ITreeNode at all, unless you have hierarchies of teams (e.g. Sports Teams could be the parent of Cricket teams).