问题
I have this product category model:
public class ProductCategory
{
public int Id { get; set; }
public int? ParentId { get; set; }
public string Title { get; set; }
}
Using the parent Id, I want to display a list of categories and sub-categories (max three levels) in a tabeled list, like so:
<table>
<tr><td colspan="3">Category #1</td></tr>
<tr><td></td><td>Category #1.1</td><td></td></tr>
<tr><td></td><td>Category #1.2</td><td></td></tr>
<tr><td colspan="2"></td><td>Category #1.2.1</td></tr>
<tr><td colspan="2"></td><td>Category #1.2.2</td></tr>
<tr><td colspan="3">Category #2</td></tr>
</table>
I tried to implement this solution, but I don't understand how I'm supposed to pass the data to the partial view. And my categories don't have a reference to children, but rather to parents.
回答1:
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.
来源:https://stackoverflow.com/questions/47694651/recursion-in-a-table-using-razor-in-asp-net-core