This is a frequently recurring problem of generating a tree from a flat list. I have caught myself relying on the two-level method described below. I would appreciate anyone suggesting a better approach that could be easily extended to multiple levels.
Description:
- Resultset is flat and contains a reference to a parentId
- Root items would have null or zero parentId. In the example code FromDb.ParseInt would handle DBNull by converting it to zero.
using (SqlDataReader reader = command.ExecuteReader()) { List<ParentDataObject> results = new List<ParentDataObject>(); ParentDataObject parent = new ParentDataObject(); ParentDataObject previousParent = null; while (reader.Read()) { parent.Id = FromDb.ParseInt(reader['ParentId']);
// Parent-level if (previousParent == null || parent.Id != previousParent.Id) { if (previousParent != null) { results.Add(previousParent); // save previously processed ParentDataObject } parent = new ParentDataObject(); // Fill parent object with data... } // Child-level ChildDataObject child = new ChildDataObject; // Fill child with data... parent.Children.Add(child); previousParentId = currentParentId; } // add last parent to results if (previousParent != null) results.Add(previousParent); }
How about something like this? (Pseudo-code)
This assumes all of your objects are homogeneous, rather than having separate parent/child classes, and also that the ordering is such that you won’t read in a child before you read in its parent… but it should work for multiple levels, and you can adapt it as required.
(If the second assumption is not true, you can read all records into the index first, then go back through the index and fix up roots and children.)