To mimic the solution you refer to, you'd have to add at least one Navigation Property to your entity. This way you can effectively enumerate the children of each ProductCategory.
I would suggest the following entity declaration, which would cause no extra side effects in the database. It has two Navigation properties for convenience:
public class ProductCategory
{
public int Id { get; set; }
public string Title { get; set; }
[ForeignKey(nameof(ParentCategory))]
public int? ParentId { get; set; }
public ProductCategory ParentCategory { get; set; } //nav.prop to parent
public ICollection<ProductCategory> Children { get; set; } //nav. prop to children
}
Now, if you have a nicely filled database set with ParentCategory records, you could query it in an action method as follows:
public IActionResult Index()
{
//get all categories, so we have each and every child in Context
var categories = yourDbContext.ProductCategories.Include(e => e.Children).ToList();
//only need top level categories in the View
var topLevelCategories = categories.Where(e => e.ParentId == null);
return View(topLevelCategories);
}
This view would then take these top level categories as a model (I would strongly recommend creating a ViewModel for this), and use a Partial to render all children recursively:
@model IEnumerable<ProductCategory>
<table>
@Html.Partial("CategoryRowPartial", Model)
</table>
Finally, the CategoryRowPartial, which also receives an IEnumerable<ProductCategory> would look like this. It calls itself recursively to display all children:
@model IEnumerable<ProductCategory>
@foreach (var category in Model)
{
<tr><td>@category.Title</td></tr>
@Html.Partial("CategoryRowPartial", category.Children)
}
Now, this doesn't take into account the level of each child nor the empty (and rather sloppy) td's & colspans. Personally, I'd use <ul> or <ol> for this. They are meant to be used to display hierarchies.
If you insist on using a <table>, I again recommend to create a specialized View Model which could hold the "depth" of each table row.