Wiki

Clone wiki

Boot.Multitenancy / Hierarchy feature

multitenancy-hierarchy.jpg

#Hierarchy feature#

This lets you create a hierarky of any object that inherits the Node class. Lets say you want to create a simple UL LI list. This is very easy with this class. This feature also allow us to create JSon data in a second. Let me show you an example.

Create a model SiteNode:

#!c#

using Boot.Multitenancy.Intrastructure.Domain; <!--Important-->
namespace......
    public class SiteNode : Node, IEntity //<!----Inherit Node class
    {
        public virtual string Text { get; set; }
        public virtual string Url { get; set; }
    }
    public class SiteNodeMap : Entity<SiteNode>
    {
        public SiteNodeMap()
        {
        //Id and ParentId is inherited from base class so dont add these in SiteNode class.
            Id(x => x.Id)
               .Column("Id") 
               .GeneratedBy.Assigned()
               .CustomType<Int32>();
            Map(p => p.ParentId);
            Map(p => p.Text);
            Map(p => p.Url);
        }
    } 
    //For simplicity I added this code in HomeController, but its better to have a viewmodel, repo...
    public ActionResult Index()
        {
            var treeData = Host.Open().All<SiteNode>()
                .ToBaseList() //Extension that Adds a Parent Child relation
                            .TreeView(c => c.Nodes, c => c.Data.Text, c=> c.Data.Url);

            return View("Index", "_Layout", treeData);
        }

    1. In model just add @Html.Raw(Model)
    2. Start the site to create the table.
    3. Open the table and add some items in it.

    For eg: 1, 0, Root, /home
        2, 1, Sub 1.1, /sub1.1
        .....

#Flatten# If you need to flatten your data add this method below as an extension. I will add it in the next release. Flatten a hierarchy makes it possible to print out items in the order their created in the hierarchy. Useful when for example creating a Treegrid or as I did for my Widget, Page Mini Admin.

pagelist.new.png

#!c#

        private static IEnumerable<NodeBase<T>> Flatten<T>(this IEnumerable<NodeBase<T>> items, 
Func<NodeBase<T>, IEnumerable<NodeBase<T>>> getChildren)
        {
            var stack = new Stack<NodeBase<T>>();
            foreach (var item in items)
                stack.Push(item);

            while (stack.Count > 0)
            {
                var current = stack.Pop();
                yield return current;

                var children = getChildren(current);
                if (children == null) continue;

                foreach (var child in children)
                    stack.Push(child);
            }
        }

        public static IEnumerable<NodeBase<T>> ToFlatten<T>(this IEnumerable<NodeBase<T>> items)
        {
            return items.Flatten(c=> c.Nodes).Reverse();
        }

     //Example use:
          Pages.ToBaseList().ToFlatten().ToList().ForEach(c => {
                var hasNodes = Pages.Where(x=> x.Id == c.Data.ParentId);
                var parent = hasNodes.Any() ? " - " : "";
                model.PageList +=string.Format(template, 
                                            c.Data.Id, 
                                            c.Data.Text, 
                                            c.Data.Url, 
                                            parent, 
                                            c.Data.Icon, 
                                            c.Data.ParentId);
            });

JSon

It easy to render data as a JsonResult.

#!c#


 public ActionResult Output()
        {
            var treeData = Host.Open()
                     .All<SiteNode>()
                        .ToBaseList()
                            .ToHierarchy();

            return Json(treeData, JsonRequestBehavior.AllowGet);
        }

Output:

[
  {
    "Data": {
      "Text": "TestRoot",
      "Url": "/",
      "Id": 1,
      "ParentId": 0
    },
    "Nodes": [
      {
        "Data": {
          "Text": "TestSub",
          "Url": "/test",
          "Id": 2,
          "ParentId": 1
        },
        "Nodes": [],
        "Parent": null
      }
    ],
    "Parent": null
  },
  {
    "Data": {
      "Text": "Forum",
      "Url": "/forum",
      "Id": 3,
      "ParentId": 0
    },
    "Nodes": [
      {
        "Data": {
          "Text": "Threads",
          "Url": "/treads",
          "Id": 4,
          "ParentId": 3
        },
        "Nodes": [],
        "Parent": null
      }
    ],
    "Parent": null
  }
]

#What's next# Currenctly I'm not satisfied with the ordering of items. I'm working on the next release where I added a Position comparer. Will also change the INode infrastructure to make it more easy to use since it's in a generic package.

The new structure as follows:

  • Node 1
  • Node 1.1
  • Node 2
  • Node 2.1
  • Node 2.2 ....
#!c#
    public interface INode<T>
    {
        Int32 Id { get; set; }
        Int32 ParentId { get; set; }
        List<T> Nodes { get; set; }
        string Position {get; set; }
    }
    //Makes it much more simpler.
   public class SiteNode : INode<SiteNode>, IEntity{} ....

        public static IEnumerable<T> OrderByPosition<T>(this IEnumerable<INode<T>> collection)
        {
            return collection
                    .OrderBy(menuPartEntry => menuPartEntry
                        .Position, new PositionComparer())
                            .Cast<T>()
                                .ToList();

        }


        public static void ReOrder<T>(this IEnumerable<INode<T>> collection, Action<INode<T>> save)
    .......

Updated