Obtain RelativeURLs of multiple TreeNode simultaneously?

Pete Hubbel asked on November 22, 2019 20:39

We are building a large menu tree and need to retrieve RelativeURLs for all TreeNodes. The TreeNode.AllChildren seems an efficient way to get a flat collection of TreeNodes, but getting the RelativeURL seems to require re-querying each node like this:

DocumentHelper.GetDocuments().FirstOrDefault(d => d.NodeGUID == target.NodeGUID)?.RelativeURL

Is there a more efficient way to do this?

Recent Answers

Peter Mogilnitski answered on November 22, 2019 21:20 (last edited on November 22, 2019 23:35)

You have query correctly, i.e. specifying type and columns will improve the query performance and you should use caching with dependencies:

var menuList = CacheHelper.Cache(cs =>
    var menu = new List<CMS.DocumentEngine.TreeNode>();
    var menuPath = "/MenuTest/";
    menu = DocumentHelper.GetDocuments("CMS.MenuItem")
        .Columns("DocumentName", "NodeLevel", "DocumentCulture", "NodeID", "NodeParentID", "DocumentURLPath", "NodeAliasPath")
        .Path(menuPath, PathTypeEnum.Children)
        .OrderBy("NodeOrder", "NodeLevel")

    if (cs.Cached)
        // set dependency based on sub tree - node|<site name>|<alias path>|childnodes 
        var dpendencyConfig = new List<string>()
        cs.CacheDependency = CacheHelper.GetCacheDependency(dpendencyConfig);
    return menu;
new CacheSettings(60, "myMenuItems_" + SiteContext.CurrentSiteName + CurrentDocument.DocumentCulture));

Now you can render it the way you want:

var itemsByParentId = menuList.ToLookup(x => x.NodeParentID);
var firstLevel = menuList.Min(x => x.NodeLevel);
var level1Nodes = menuList.Where(x => x.NodeLevel == firstLevel);

var sbMenu = new StringBuilder();

foreach (var menuItem in level1Nodes)
    sbMenu.Append($"<li><a href='{menuItem.RelativeURL}'>{menuItem.DocumentName}</li>");
    foreach (var subMenuItem in itemsByParentId[menuItem.NodeID])
        sbMenu.Append($"<li><a href='{subMenuItem.RelativeURL}'>{subMenuItem.DocumentName}</li>");

var result = sbMenu.ToString();

The code above is just to give you an idea how to approach. Adjust it to your needs.

1 votesVote for this answer Mark as a Correct answer

   Please, sign in to be able to submit a new answer.