EF Core 7.0.4如何获取Blazor Server中文件夹的所有父级
解决EF Core获取文件夹所有父级的方案
方法1:用EF Core递归CTE查询(推荐)
EF Core 7原生支持递归CTE(公共表表达式),可以直接从数据库层面一次性拉取所有父级数据,不用反复写Include。
实现代码
先假设你的Folder实体是这样的:
public class Folder { public int Id { get; set; } public string Name { get; set; } public int? ParentId { get; set; } public Folder Parent { get; set; } public ICollection<Folder> Children { get; set; } }
在FolderService里写递归查询方法:
public async Task<List<Folder>> GetAllAncestors(int folderId) { // 用CTE递归查询所有父级,排除当前文件夹本身 var ancestors = await _dbContext.Folders .FromSqlRaw(@" WITH RecursiveAncestors AS ( SELECT Id, Name, ParentId FROM Folders WHERE Id = {0} UNION ALL SELECT f.Id, f.Name, f.ParentId FROM Folders f INNER JOIN RecursiveAncestors ra ON f.Id = ra.ParentId ) SELECT * FROM RecursiveAncestors WHERE Id != {0}", folderId) .ToListAsync(); // 反转后得到从根文件夹到当前文件夹的层级顺序 ancestors.Reverse(); return ancestors; }
这种方式性能最优,因为所有逻辑在数据库端完成,只走一次查询。
方法2:延迟加载+手动递归
如果你的项目已经开启了EF Core延迟加载,可以通过循环遍历Parent属性,逐层加载父级。
实现步骤
- 先确保启用延迟加载:
// 在DbContext的OnConfiguring方法里配置 protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { optionsBuilder.UseLazyLoadingProxies() .UseSqlServer("你的数据库连接字符串"); }
- 服务层方法实现:
public async Task<List<Folder>> GetAllAncestors(int folderId) { var ancestors = new List<Folder>(); var currentFolder = await _dbContext.Folders.FindAsync(folderId); // 循环加载父级直到没有父节点 while (currentFolder?.Parent != null) { await _dbContext.Entry(currentFolder) .Reference(f => f.Parent) .LoadAsync(); ancestors.Add(currentFolder.Parent); currentFolder = currentFolder.Parent; } // 反转顺序得到根到当前文件夹的路径 ancestors.Reverse(); return ancestors; }
这种方式适合数据量不大的场景,每次加载一个父级,会产生多次数据库查询。
方法3:内存中递归(小体量场景)
如果你的文件夹总数不多,可以一次性把所有文件夹加载到内存,然后在内存里递归找父级,减少数据库交互次数。
实现代码
public async Task<List<Folder>> GetAllAncestors(int folderId) { var allFolders = await _dbContext.Folders.ToListAsync(); var ancestors = new List<Folder>(); var currentId = folderId; while (true) { var currentFolder = allFolders.FirstOrDefault(f => f.Id == currentId); if (currentFolder?.ParentId == null) break; var parentFolder = allFolders.First(f => f.Id == currentFolder.ParentId.Value); ancestors.Add(parentFolder); currentId = parentFolder.Id; } ancestors.Reverse(); return ancestors; }
这种方式适合小型系统,文件夹数量少的情况,避免多次查库。
面包屑生成示例
在Blazor组件里调用服务方法后,直接遍历生成面包屑:
@inject FolderService _folderService @if (breadcrumbs != null && currentFolder != null) { <nav aria-label="breadcrumb"> <ol class="breadcrumb"> @foreach (var folder in breadcrumbs) { <li class="breadcrumb-item"> <a href="/folders/@folder.Id">@folder.Name</a> </li> } <li class="breadcrumb-item active" aria-current="page">@currentFolder.Name</li> </ol> </nav> } @code { [Parameter] public int FolderId { get; set; } private List<Folder> breadcrumbs; private Folder currentFolder; protected override async Task OnInitializedAsync() { currentFolder = await _folderService.GetFolderById(FolderId); breadcrumbs = await _folderService.GetAllAncestors(FolderId); } }
内容的提问来源于stack exchange,提问作者baseballr
相关产品推荐
相关产品推荐

