Blazor Admin 关联表怎么处理?Navigate、Include、Join 实战
后台开发里关联表几乎是必选项订单要显示客户名、文章要选专栏、用户要分配角色、菜单要挂父子。这篇讲 EasyAdminBlazor 里关联数据从建模到查询、展示、编辑的完整做法。一、四种关联四种 Navigate 写法FreeSql 用[Navigate]描述关联框架的实体已经给出了四类范例。1. 多对一最常用文章属于一个专栏[Table(Nameblog_article)]publicpartialclassArticle:ApprovalEntityFull{/// summary随笔专栏/summary[DisplayName(随笔专栏)][Required]publiclong?ClassifyId{get;set;}publicClassifyClassify{get;set;}default!;}这里ClassifyId是外键列Classify是导航属性。注意仓库里的示例实体并没有在Classify上写[Navigate(nameof(ClassifyId))]——FreeSql 会按命名约定自动识别ClassifyId与Classify的关系。如果你的命名不符合约定就显式标注[Navigate(nameof(ClassifyId))]publicClassifyClassify{get;set;}default!;2. 一对多反向导航partialclassSysUser{[Navigate(nameof(SysRoleUser.UserId))][JsonIgnore]publicListSysRoleUserRoleUsers{get;set;}[];}3. 多对多publicclassSysRole:Entity{[JsonIgnore][Navigate(ManyToManytypeof(SysRoleUser))]publicListSysUserUsers{get;set;}[];[JsonIgnore][Navigate(ManyToManytypeof(SysRoleMenu))]publicListSysMenuMenus{get;set;}[];}中间表是显式定义的实体publicclassSysRoleMenu{publiclongRoleId{get;set;}publiclongMenuId{get;set;}publicSysRoleRole{get;set;}default!;publicSysMenuMenu{get;set;}default!;}4. 自关联树形publicpartialclassSysMenu:EntityCreated,IHasParentIdlong{[Navigate(nameof(ParentId))][JsonIgnore]publicSysMenu?Parent{get;set;}[Navigate(nameof(ParentId))][JsonIgnore]publicListSysMenuChilds{get;set;}[];publiclongParentId{get;set;}}注意导航属性上的[JsonIgnore]这些是 ORM 层面的对象图序列化给前端时容易产生循环引用或体积膨胀所以框架统一加了忽略。二、查询Include 与 IncludeMany1. 多对一用 IncludeprivatevoidOnBeforeQuery(AdminQueryEventArgsArticlee){e.Select.Include(aa.Classify);}2. 多对多用 IncludeMany角色页需要把这个角色有哪些菜单一起查出来因为点击行时要回显勾选状态privatevoidOnBeforeQuery(AdminQueryEventArgsSysRolee){e.Select.WhereIf(!admin.IsAdmin,xx.IsAdministratorfalse);if(!e.IsExport){e.Select.IncludeMany(xx.Menus);}}两行代码包含两个经验WhereIf做条件过滤非管理员看不到超级管理员角色导出时跳过IncludeManyIsExport判断避免了导出上千行时把每行的菜单集合都拉一遍的灾难性性能问题AdminQueryEventArgs的注释里明确写了这一点。3. 不带导航的查询默认更轻如果只是要显示分类 Id而不是分类名称就不要Include。导航属性的加载是有成本的尤其是在列表页。三、表格展示关联名称关联名称不能直接绑ClassifyId要用Template取导航属性TableColumn bind-Fieldcontext.ClassifyId Filterabletrue Template Contextvv.Row.Classify?.ClassifyName/Template FilterTemplate FilterProvider AdminSelectEntityFilter TItemClassify GetTextx x.ClassifyName / /FilterProvider /FilterTemplate /TableColumn三件事同时完成列绑定的是外键字段ClassifyId这样排序、筛选都作用在数据库列上显示的是导航属性Classify?.ClassifyName列头筛选用AdminSelectEntityFilter选一个专栏。?.不是多余的如果某行的外键指向一个已被删除的分类导航属性就是 null加了?.才不会抛异常。按关联字段模糊搜索想按分类名称模糊搜索用AdminSelectEntityFilterGenericTableColumn bind-Fieldcontext.Title Filterabletrue Searchabletrue FilterTemplate FilterProvider AdminSelectEntityFilterGeneric TItemClassify TKeystring FilterActionFilterAction.Contains GetValueaa.ClassifyName GetTextx x.ClassifyName / /FilterProvider /FilterTemplate /TableColumnGetValue决定筛选值取什么这里取分类名FilterAction.Contains决定是模糊匹配。四、表单里选关联三个组件1. AdminSelectEntity只绑 IdAdminSelectEntity TItemClassify TKeylong? bind-ValueModel.ClassifyId GetTexte e.ClassifyName ShowSearch /参数源码[Parameter]publicExpressionFuncTItem,bool?Where{get;set;}[Parameter]publicFuncTItem,stringGetText{get;set;}xx?.ToString()??string.Empty;[Parameter]publicFuncTItem,string?GetValue{get;set;}[Parameter]publicTimeSpanCacheDuration{get;set;}TimeSpan.FromSeconds(30);注意CacheDuration默认是 30 秒。2. AdminSelectTable绑整个实体需要把选中的实体对象也带回来比如要读它的多个字段时用这个AdminSelectTable TItemSysUser bind-ValueIdselectedUserId GetText(u u.Nickname) TableColumns TableColumn bind-Fieldcontext.Username Text用户名 / TableColumn bind-Fieldcontext.Nickname Text昵称 / /TableColumns /AdminSelectTable它同时支持bind-Value完整实体和bind-ValueId主键弹窗里的列可以自定义。3. 是否需要数据权限AdminSelectEntity/AdminMultiSelect/AdminSelectTable都支持UseDataPermission用法与AdminTable一致AdminSelectEntity TItemSysUser TKeylong bind-ValueIdModel.AuditorId GetTextu u.Nickname UseDataPermissiontrue /打开之后能选谁就受当前用户的数据权限约束避免选到一个自己根本无权查看的人。五、多对多编辑角色分配菜单的真实实现Pages/Role.razor是一个完整的多对多编辑范例左边角色表格右边菜单树。1. 点击行回显已选privateasyncTaskOnClickRowCallback(SysRolerow){selectrow;varroleMenuIdsrow.Menus.Select(mm.Id).ToList();menuSelectionTree?.UpdateTreeSelection(roleMenuIds);awaitInvokeAsync(StateHasChanged);}row.Menus之所以有值是因为查询时IncludeMany(x x.Menus)已经加载了。2. 保存更新关联表[AdminButton(alloc_menus)][OperationLog(修改角色菜单权限)]privateasyncTaskOnSaveMenu(){if(select!null){if(select.Menusnull||select.Menus.Count0){awaitSwalService.Warning(CommonLocalizer[请至少选择一个菜单权限]);return;}await_repo.UpdateAsync(select);awaitadmin.InvalidatePermissionCacheAsync();awaitToastService.Success(CommonLocalizer[保存数据],CommonLocalizer[权限保存成功]);}}三个关键点[AdminButton(alloc_menus)]方法级权限没有这个按钮权限直接拦截[OperationLog(修改角色菜单权限)]审计留痕InvalidatePermissionCacheAsync()角色-菜单关系变了权限缓存必须立即失效否则用户要等 30 分钟才生效。3. 删除前的引用检查删除角色前要确认没人用它varroleIdse.Items.Select(xx.Id).ToList();varusedCountawait_repo.Orm.SelectSysRoleUser().Where(xroleIds.Contains(x.RoleId)).CountAsync();if(usedCount0){awaitSwalService.Error(CommonLocalizer[该角色已分配给用户不能删除]);e.Canceltrue;}这是关联表最典型的引用完整性处理先查中间表有人用就拦住删除。六、IgnoreSearchColumns导航属性不能当筛选列这是关联表最容易踩的坑。页面里只要有导航集合就要在AdminTable上声明忽略AdminTable TItemSysUser TKeylong IgnoreSearchColumnsx new { x.Roles, x.Messages } ... /原因在第 05 篇讲过框架会把表格的筛选条件翻译成数据库条件导航属性不是数据库列传下去会报无法匹配 xxx。IgnoreSearchColumns在OnParametersSetAsync的最前面就会被解析GetIgnoredPropertyNames()保证首次渲染抢跑查询时列表已经就绪。七、性能关联查询的几个取舍做法代价建议列表页Include多对一每条多一次 JOIN需要显示关联名称时才加列表页IncludeMany多对多数据量随关联数放大只在确实需要时用如角色页回显菜单导出时Include行数 × 关联数非常慢用IsExport跳过关联筛选AdminSelectEntityFilterGeneric子查询/EXISTS关联表的外键列建索引导航属性被当作筛选字段直接报错加入IgnoreSearchColumns一条经验列表页尽量只查需要的列关联名称用投影或按需加载编辑页拿到完整对象后导航加载可以更宽松。八、主子表明细怎么办先说实话框架没有专门的主从表/明细表组件。EditTemplate只是一个普通的 Blazor 组件插槽。如果需要一张订单下面有多条明细可行的做法是!-- 订单编辑模板里嵌一个绑定当前订单的明细表格 -- AdminTable TItemOrderItem TKeylong OnBeforeQueryOnBeforeQueryItems ... / code { private void OnBeforeQueryItems(AdminQueryEventArgsOrderItem e) { e.Select.Where(x x.OrderId Model.Id); // 只查当前单据的明细 } }要注意两点主单据尚未保存Id 0时没有明细可挂通常做法是先保存主表再编辑明细明细的保存/删除要自己处理与主表的从属关系级联删除、必填校验等。这属于业务编排框架提供的是组件能力而不是固定模式。九、常见问题现象原因处理关联名称为空导航属性没加载在OnBeforeQuery里Include报无法匹配 xxx导航属性参与了筛选加入IgnoreSearchColumns多对多保存没生效只改了主表没更新中间表参考Role.razorIncludeManyUpdateAsync改了角色/菜单权限不生效权限缓存未失效调用InvalidatePermissionCacheAsync()导出慢到超时导出时加载了导航集合用IsExport判断后跳过删除时报外键错误关联数据未清理删除前查中间表/子表或做级联十、小结关联表在 EasyAdminBlazor 里的处理套路可以总结成四句话建模外键用xxxId导航用[Navigate]约定优于配置命名不符时显式标注查询需要展示才Include/IncludeMany导出时跳过展示列绑外键、显示导航值、筛选用AdminSelectEntityFilter(Generic)编辑选单个关联用AdminSelectEntity多对多用中间表 IncludeManyUpdateAsync并记得让缓存失效。再加一条纪律所有导航属性都放进IgnoreSearchColumns。这一条能省掉大量无法匹配 xxx的排查时间。如果你正在用 .NET 10 Blazor 做后台关联表是绕不开的场景。EasyAdminBlazor 在实体导航、查询加载、关联选择器、多对多编辑上都给了现成做法可以照着改。文档https://easyadmin.wang-zhan.com.cn/doc源码https://gitee.com/gudufy/EasyAdminBlazor

相关新闻

JavaWeb图书管理系统源码详解:部署、阅读与二次开发实战

JavaWeb图书管理系统源码详解:部署、阅读与二次开发实战

简介:面向JavaWeb课程设计、期末大作业与入门学习者的图书管理系统完整源码包,覆盖图书查询、借阅、归还等核心流程,附数据库脚本和详细文档说明。压缩包共278个文件,约11.67MB;其中45个Java后端源码、19个JSP页面配合…

2026/10/19 0:42:06 阅读更多 →
机器学习分类算法实战指南:原理、选型与评估指标

机器学习分类算法实战指南:原理、选型与评估指标

机器学习里有一类问题,几乎占了业务场景的大半壁江山,就是分类。垃圾邮件识别、信用卡欺诈检测、图片内容识别、疾病风险预测、用户流失预警,这些看似风马牛不相及的领域,落到算法层面,核心都是同一件事:给…

2026/11/8 2:00:52 阅读更多 →
Infection Monkey 快速上手:从零启动你的第一次网络渗透模拟

Infection Monkey 快速上手:从零启动你的第一次网络渗透模拟

网络安全应用安全 【免费下载链接】monkey Infection Monkey - An open-source adversary emulation platform 项目地址: https://gitcode.com/gh_mirrors/mo/monkey 点击查看 免费下载 本篇指南面向初次使用 Infection Monkey(开源对抗模拟平台&#x…

2026/10/19 0:42:09 阅读更多 →

最新新闻

Electron桌面应用开发实战:从环境搭建到打包发布全流程

Electron桌面应用开发实战:从环境搭建到打包发布全流程

做前端这些年,我大部分时间都在跟浏览器标签页打交道,直到第一次把桌面应用跑起来,才发现原来自己一直被限制在地址栏和刷新按钮围起来的框框里。Electron这个词,最开始是在某段时间频繁出现在同事的讨论里,一个用HTML…

2026/11/8 1:19:03 阅读更多 →
滑盖智能锁T109深度解析:结构原理、安装调试与故障排查

滑盖智能锁T109深度解析:结构原理、安装调试与故障排查

简介:亚太天能T109滑盖智能锁产品说明书是一份PDF格式的官方技术文档,主要面向智能锁安装人员、终端用户及售后维护者,帮助快速掌握产品安装、配置与常见故障处理。全包仅1个PDF文件,大小4.37MB,内容结构清晰&#xff…

2026/11/7 12:08:40 阅读更多 →
PMSM弱磁控制原理与Simulink建模:高速AGV驱动系统设计指南

PMSM弱磁控制原理与Simulink建模:高速AGV驱动系统设计指南

上个月我在调试一台高速AGV的驱动系统,整车要求空载跑到8m/s,电机转速已经拉到额定点,驱动器的输出电压也顶到了母线电压极限附近。再往上踩速度指令,转速纹丝不动,三相电流反而开始震荡。那会儿我的第一反应就是&…

2026/11/8 1:35:05 阅读更多 →
C++核心知识点:从内存管理到STL的实战指南

C++核心知识点:从内存管理到STL的实战指南

C 这门语言我前前后后折腾了十几年,用它写过嵌入式驱动、做过游戏服务端,也搭过基础组件库。每次看到新人一头扎进"C 核心知识点"这个搜索词,我其实挺感慨的——这门语言的难点从来不是语法多,而是知识点之间的耦合太深…

2026/11/8 1:38:41 阅读更多 →
T109滑盖智能锁怎么装?安装调试与故障排查全攻略

T109滑盖智能锁怎么装?安装调试与故障排查全攻略

简介:亚太天能T109滑盖智能锁产品说明书以PDF格式发布,适合智能锁用户、安装人员与售后维修人员阅读。内容围绕T109系列指纹密码刷卡锁展开,先介绍前面板、后面板、锁体、机械钥匙、电池盒盖等部件名称与功能,再给出完整安装步骤&…

2026/11/7 12:08:40 阅读更多 →
LLM知识降熵:从信息垄断到理解权下放

LLM知识降熵:从信息垄断到理解权下放

你有没有过这种经历:翻开源码注释、论文摘要或者一份专业报告,每个字都认识,连在一起却像天书。想找人聊聊,身边要么没人懂,要么懂的懒得跟你解释。后来我试着把同一段内容丢给一个大语言模型,几秒钟之后&a…

2026/11/8 1:23:14 阅读更多 →

日新闻

周新闻

月新闻