Blazor Admin 关联表怎么处理?Navigate、Include、Join 实战

发布时间:2026/10/8 19:32:43

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
延伸阅读

更多相关文章

2026/10/8 20:48:03

递归自改进与有限自细化:从刷分陷阱到可控的AI自我进化工程

上个月我跑了一个小小的递归自改进实验:用一个大模型当“优化器”,去改另一个模型的系统提示词,目标很简单,把代码生成通过率从60%抬到80%。第一轮和第二轮确实在涨,到第五轮就出现了诡异的变化:模型开始在…

2026/10/8 20:48:03

GTC 2026前瞻与英伟达驱动排障实战:从报错到环境优化

GTC 2026要来了,但我翻了翻后台留言和各个群里最近的讨论,发现大家关心的事跑了偏:新卡什么时候出、DLSS还能怎么吹,这些反倒是其次。真正让大多数人头疼的,是驱动。0x80070002报错、安装包损坏、桌面图标凭空消失、De…

2026/10/8 20:48:03

从AutoResearch看科研自动化:当LLM成为软件的基本执行单元

前阵子我在刷信息流的时候,被 Karpathy 在 GitHub 上公开的 AutoResearch 实验报告链接勾住了。本来想着扫一眼就划走,结果一口气读了两遍,又顺着他把他在 X 上关于 "software is changing" 的讨论全部翻了出来。这几年号称“AI 科…

2026/10/8 20:48:03

AI大模型API聚合平台:2026年工程落地的确定性基础设施

1. 为什么2026年团队集体转向聚合平台——不是跟风,是API对接成本崩盘后的理性自救2026年春天,我帮三家不同行业的客户做AI大模型集成方案:一家做工业质检的制造企业,一家做服装AI试穿的电商公司,还有一家做古玩鉴定的…

2026/10/8 20:48:03

SSM高校考勤管理系统毕业设计:需求、实现与答辩全攻略

每年毕业季,Java方向的选题里,“SSM高校考勤管理系统”几乎是出镜率最高的题目之一。原因很简单:它既有Spring、SpringMVC、MyBatis这套SSM框架的完整应用,又有学生、教师、管理员三种角色的权限区分,还有签到、请假、…

2026/10/8 10:03:18

Jev+Agent接管浏览器:browser-use实战与jev-ultrafast性能优化

1. 从“Jev”说起:为什么我要把Agent接进浏览器“Jev”这个词最近在圈子里出现的频率越来越高,很多人第一次听到会以为是某个新模型的名字,其实它更像是一种思路——把Jev模型的能力当作底座,通过Agent的方式去接管浏览器&#xf…

2026/10/8 10:03:20

多智能体集群实战:DeepAgents编排、MCP与A2A协议及Skills体系

1. 从"单兵作战"到"集群协同":多智能体编排到底在解决什么问题如果你最近在折腾 Agent 相关的东西,大概率会有一种感觉:单个 Agent 能做的事情,其实很快就摸到天花板了。你给它一个提示词,挂几个工…

2026/10/8 6:05:44

无源低通滤波器设计实战:从RC到LC,手把手教你避开那些坑

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/8 0:02:17

自然数立方等于连续奇数之和:从证明到编程验证

十几年来我一直游走在数学科普和编程教学这两块内容之间,对“看起来像魔法、拆开全是数学”的结论总是格外敏感。最近翻资料时又撞见一句话:任何一个自然数 m 的立方,都可以写成 m 个连续奇数之和。2 的立方等于 3 加 5,3 的立方等…

2026/10/8 0:02:17

C#上位机SSH连接实战:用SSH.NET补齐超时、批量与密钥认证

简介:这是一份基于 C# 开发的 SSH 连接功能半成品工程,原本作为另一个主项目的子功能模块,现独立打包分享。工程采用 WinForms 界面,包含源码、解决方案、安装部署工程、NuGet 依赖包及说明文档,适合正在做远程连接、网…

2026/10/8 0:02:17

Java SpringBoot一体化智能售后系统设计与实现全解析

毕业设计年年做,Java Web 方向的题目翻来覆去就那么几个,但“一体化智能售后系统”这个题,每次看到我都觉得值得认真聊一聊。它不是一个简单 curd 堆出来的管理系统,而是把客户、工单、派单、处理、回访、统计整条链路串起来的一套…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑