amartin amartin - 1 year ago 26
ASP.NET (C#) Question

Working with a Model class that has a foreign/navigation key to itself - pt. 2

This is related to this question. (I don't have the necessary reputation to post comments to that discussion)

Assuming we have the same model class

public class Category
public int CategoryID { get; set; }
public string CategoryName { get; set; }
public int? ParentCategoryID { get; set; }
public string CategoryDesc { get; set; }

public virtual Category ParentCategory { get; set; }

public virtual ICollection<Category> SubCategories{ get; set; }

public virtual ICollection<Product> Products { get; set; }

and use this query

var topCategories = dbStore.Categories.ToList().Where(category => category.ParentCategoryID == null);

What would be considered best practice for organizing and using the Collection

I have a similar situation where in my case the
could be 7 or 8 levels deep, and I need to know where each
is within the hierarchy in order to build a View from this data.

I'm using jQuery treetable, and it requires everything to be in the hierarchical order, and for there to be an
that references its parent for each
in order for the collapsible tree to work.

I believe I can make this work by creating separate variables for each level of the hierarchy (by running queries on
and making individual Collections for each level) in the the method that builds the ViewModel and returns the View, but I'm curious to know if there's a cleaner / more elegant way to do this.


Answer Source

I found the solution to what I'm trying to do in this post.

I'm certain I didn't ask the original question in a clear enough way, but wanted to add this in case anyone else ended up down the rabbit hole I was in on this subject.

I still have some reading to do on this because I don't fully understand all of it, but what I was ultimately looking for was a topological sort, as referenced in the linked SO post above.

Here is the code from the referenced post, edited for this post.

If anyone is willing to walk through everything that's happening here, I would greatly appreciate it.

class FlattenTree
  // map each item to its children
  ILookup<Category, Category> mapping;

  public FlattenTree(IEnumerable<Category> list)
    var itemLookup = list.ToDictionary(item => item.ID);
    mapping = list.Where(i => i.ParentCategoryID.HasValue)
                  .ToLookup(i => itemLookup[i.ParentCategoryID.Value]);

  IEnumerable<Item> YieldItemAndChildren(Item node)
    yield return node;
    foreach (var child in mapping[node].OrderBy(i => i.CategoryName))
        foreach (var grandchild in YieldItemAndChildren(child))
            yield return grandchild;

  public IEnumerable<Category> Sort()
    return from grouping in mapping
           let item = grouping.Key
           where item.ParentCategoryID == null
           orderby item.CategoryName
           from child in YieldItemAndChildren(item)
           select child;