Click here to Skip to main content
14,236,057 members
Rate this:
Please Sign up or sign in to vote.
I have a data table as following

ID    Name   ParentID
1      A       0
2      B       1
3      C       1
4      D       2
5      E       3
6      F       4


I want this as a List<chart>

//Chart.cs
 public int ID { get; set; }
 public string Name { get; set; }
 public string ParentID{ get; set; }
 public List<chart> lstChild{ get; set; }


What I have tried:

I have tried this function:

public static void MakeTree(DataTable dt, clsChart parent)
        {
            foreach (DataRow row in dt.AsEnumerable().Where(x => x.Field<int>("ParentID") == parent.ID))
            {
                if (parent.lstChildren == null)
                {
                    parent.lstChildren = new List<clschart>();
                }
                clsChart newNode = new clsChart();
                newNode.Name = row.Field<string>("Name");
                newNode.ID = row.Field<int>("EntryID");
                parent.lstChildren.Add(newNode);
                MakeTree(dt, newNode);
            }
        }


But it doesn't return List<>, it returns the class
Posted
Updated 28-Mar-19 19:36pm
v2
Rate this:
Please Sign up or sign in to vote.

Solution 3

As to me, your datatable is designed properly for hierarchical data model[^]. That's why a chart model should reflect to a datatable model.
public class chart
{
	public int ID { get; set; }
 	public string Name { get; set; }
	public int ParentID{ get; set; }
}


This is very easy to create a List<chart> from your datatable:
List<chart> charts = dt.AsEnumerable()
    .Select(dr=> new chart()
        {
            ID=dr.Field<int>("ID"),
            Name=dr.Field<string>("Name"),
            ParentID=dr.Field<int>("ParentID")
        })
    .ToList();


Above model is a "flat" version of hierarchical data. In case you want to create more advanced hierarchical structure, please, read this: Recursive Hierarchical Joins in C# and LINQ - Bitlush[^]
   
Rate this:
Please Sign up or sign in to vote.

Solution 1

You can recursively create (and link) your nodes, but you also need a "master list" that you add to when you create each node.

The "master list" represents the fully expanded tree; a node is expandable / collapsible if it has children.

"Canned" tree views maintain an internal "tree view list" (same thing).

The "level" of each item determines the indenting.

Adding a "level number" is useful when creating tree. With a level number, you can also infer the parent, if any, when using compound keys.
   
Rate this:
Please Sign up or sign in to vote.

Solution 2

Firstly, ParentID should be an int, not a string

Secondly, you don't need recursion at all, and provided your parent nodes are always defined before their children, you can use a single loop. (If it's a random order, then create a node collection first, and then loop through that afterwards:
class Chart
    {
    private static Dictionary<int, Chart> all = new Dictionary<int, Chart>();
    public int ID { get; set; }
    public string Name { get; set; }
    public int ParentID { get; set; }
    public List<Chart> Children { get; set; } = new List<Chart>();
    private Chart(DataRow row)
        {
        ID = (int)row["ID"];
        Name = (string)row["Name"];
        ParentID = (int)row["ParentID"];
        all[ID] = this;
        }
    public static Chart MakeTree(DataTable dt)
        {
        List<Chart> nodes = new List<Chart>();
        Chart root = null;
        foreach (DataRow row in dt.AsEnumerable())
            {
            Chart node = new Chart(row);
            if (node.ParentID == 0)
                {
                if (root != null) throw new ArgumentException("Too many ROOT nodes: only one was expected.");
                root = node;
                }
            else
                {
                if (root == null) throw new ArgumentException("ROOT node has not been defined: one is required.");
                Chart parent = all[node.ParentID];
                parent.Children.Add(node);
                }
            }
        return root;
        }
    }

DataTable dt = new DataTable();
dt.Columns.Add("ID", typeof(int));
dt.Columns.Add("Name", typeof(string));
dt.Columns.Add("ParentID", typeof(int));
dt.Rows.Add(1, "A", 0);
dt.Rows.Add(2, "B", 1);
dt.Rows.Add(3, "C", 1);
dt.Rows.Add(4, "D", 2);
dt.Rows.Add(5, "E", 3);
dt.Rows.Add(6, "F", 4);
Chart root = Chart.MakeTree(dt);
   
Comments
prapti.n3 27-Mar-19 4:23am
   
But I want it in List<chart> type not as Chart object
OriginalGriff 27-Mar-19 4:36am
   
You have one root node: this contains a List of all the child Chart items. The only List of all items you could create would contain one item: the root node. All the others are child nodes of that root.

So why would you want that at all?
prapti.n3 27-Mar-19 4:40am
   
Because this is only an example. The data on which i am working has 3-4 root with parent ID 0.
OriginalGriff 27-Mar-19 4:56am
   
So create a "dummy node" with ID 0, and then return the child list from that!

Or, add a collection of nodes to return, and add all nodes with a parent of 0 to that instead of limiting it to one root.
Rate this:
Please Sign up or sign in to vote.

Solution 4

List<clschart> lstChart = new List<clschart>();
string JSONresult;

//var roots = dt.AsEnumerable().ToList();
lstChart = clsDataTables.ConvertDataTable<clschart>(dt);
var roots = lstChart.Where(f => f.ParentID == 0).ToList();
//(from n in dt.AsEnumerable() where n.Field<int>("ParentID") == 0 group n by n.Field<int>("ParentID")).ToList();
foreach (var root in roots)
clsChart.BuildTree(root, lstChart);

JSONresult = JsonConvert.SerializeObject(roots, Formatting.Indented);
   

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)




CodeProject, 503-250 Ferrand Drive Toronto Ontario, M3C 3G8 Canada +1 416-849-8900 x 100