恒美微站 Logo 恒美微站
  • 首页
  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心
  • 联系我们

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

  • 首页
  • 资讯中心
  • /
  • Blazor Admin 关联表怎么处理?Navigate、Include、Join 实战

相关资讯

基于springboot宠物领养系统-计算机毕设 附源码【课程设计】94217 2026/10/8 19:27:22
DeepSeek-R1 模型架构拆解:从 MoE 到推理链路的工程视角 2026/10/8 19:27:22
EasyClaw 全版本选型实操指南:基于 OpenClaw 的 AI Agent 个人 / 团队 / 企业落地全攻略|TaoToken 统一 Key 接入 2026/10/8 19:27:22

最新资讯

Python模拟Ethernet帧发送:从拼帧到CRC校验全解析
Ubuntu 24.04部署MySQL/Redis/Nginx与自动备份全记录
ThinkPHP与Laravel开发微信小程序美妆商城:选型、落地与踩坑全记录
Mac mini打造B站24小时AI评论助理实战指南
Spring Boot + Vue教室图书馆预约系统:从需求到部署全解析
虚拟机创建到配置全攻略:从选型到踩坑排查

今日推荐

context-mode实战指南:从全量塞入到结构化裁剪与检索增强
大模型对话上下文管理实战:三种模式与Token优化
抖音用户主页视频数据爬虫详解:点赞、收藏、分享字段抓取与 TaoToken 统一 Key 配置

本周热门

MR25H40CDF + PIC18F65K40:工业记录仪高可靠存储实战
基于STM32的数控恒压恒流电源设计:从硬件到PID调参全解析
LT9211 MIPI重定时器原理与双路扇出实战指南

本月精选

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证
2026 大模型集体涨价:用 Python 做企业 Token 成本测算与选型避坑(附配置)

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

发布时间:2026/10/8 19:32:23
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

关于恒美微站

恒美微站专注于为个体商户、工作室提供极简自助建站服务,让每个人都能轻松拥有专业网站。

快速链接

  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心

服务项目

  • 可视化建站
  • 拖拽编辑
  • 主题定制
  • SEO 优化
  • 网站托管

联系方式

  • 📍 地址:北京市朝阳区建国路 88 号
  • 📞 电话:400-888-8888
  • ✉️ 邮箱:info@hmyw.cn
  • 🕐 时间:周一至周日 9:00-18:00

© 2024 恒美微站 hmyw.cn 版权所有 | 京 ICP 备 12345678 号