了解です。
先ほどの「親カテゴリ → 子カテゴリ」の階層ドロップダウン例を、より汎用的で**多階層対応(再帰描画)**に改良したASP.NET Core MVCコードに再生成します。
これにより、DBに「親 → 子 → 孫」などの階層があっても自動的に表示できます。
1. モデル定義(Category)
// Models/Category.cs
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
public class Category
{
public int Id { get; set; }
[Required]
public string Name { get; set; }
public int? ParentId { get; set; }
// ナビゲーションプロパティ
public Category Parent { get; set; }
public ICollection<Category> Children { get; set; } = new List<Category>();
}
2. DbContext設定
// Data/ApplicationDbContext.cs
using Microsoft.EntityFrameworkCore;
public class ApplicationDbContext : DbContext
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options) { }
public DbSet<Category> Categories { get; set; }
}
3. 階層データ取得サービス(再帰構築)
// Services/CategoryService.cs
using Microsoft.EntityFrameworkCore;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
public class CategoryService
{
private readonly ApplicationDbContext _context;
public CategoryService(ApplicationDbContext context)
{
_context = context;
}
public async Task<List<Category>> GetCategoryHierarchyAsync()
{
var categories = await _context.Categories.ToListAsync();
return BuildHierarchy(categories, null);
}
// 再帰的に階層構造を構築
private List<Category> BuildHierarchy(List<Category> all, int? parentId)
{
return all
.Where(c => c.ParentId == parentId)
.Select(c => {
c.Children = BuildHierarchy(all, c.Id);
return c;
})
.ToList();
}
}
4. コントローラー
// Controllers/MenuController.cs
using Microsoft.AspNetCore.Mvc;
using System.Threading.Tasks;
public class MenuController : Controller
{
private readonly CategoryService _categoryService;
public MenuController(CategoryService categoryService)
{
_categoryService = categoryService;
}
public async Task<IActionResult> Index()
{
var hierarchy = await _categoryService.GetCategoryHierarchyAsync();
return View(hierarchy);
}
}
5. View(再帰描画ヘルパー付き階層ドロップダウン)
@model List<Category>
@functions {
// 再帰的に<option>を描画
void RenderOptions(List<Category> categories, string prefix)
{
foreach (var cat in categories)
{
<option value="@cat.Id">@prefix@cat.Name</option>
if (cat.Children.Any())
{
RenderOptions(cat.Children, prefix + "-- ");
}
}
}
}
<select id="categoryDropdown" class="form-select">
<option value="">-- カテゴリを選択 --</option>
@RenderOptions(Model, "")
</select>
6. Program.cs(サービス登録)
using Microsoft.EntityFrameworkCore;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection")));
builder.Services.AddScoped<CategoryService>();
builder.Services.AddControllersWithViews();
var app = builder.Build();
app.MapDefaultControllerRoute();
app.Run();
改良ポイント
- 多階層対応
再帰関数RenderOptionsで孫カテゴリまで自動描画。階層が深くても対応可能。 - 階層構築ロジック
BuildHierarchyで全カテゴリリストからツリー構造を生成。 - 見やすい階層表示
子カテゴリは--などのプレフィックスでインデント表示。
このコードは、DBに以下のようなデータがあれば階層的に表示されます。
| Id | Name | ParentId |
|---|
| 1 | 家電 | NULL |
| 2 | テレビ | 1 |
| 3 | 液晶テレビ | 2 |
| 4 | 冷蔵庫 | 1 |
| 5 | ファッション | NULL |
| 6 | メンズ | 5 |
表示例:
家電
-- テレビ
---- 液晶テレビ
-- 冷蔵庫
ファッション
-- メンズ
もし希望なら、この階層ドロップダウンを**Ajax連動型(親選択で子を動的ロード)**にするコードも作れます。
こちらはUIがさらに使いやすくなります。
作りますか?
Ajax連動版にすれば、選択時に必要な階層だけ読み込めます。
Powered by Froala Editor