序列化 JSON 时崩了?99% 是 EF 延迟加载惹的祸,三种解法拿走不谢
一、先看一个“翻车”现场假设我们有这么三层数据主表fin_voucher_rule_master凭证规则明细表fin_voucher_rule_detail规则明细条件表fin_voucher_rule_condition明细下的条件关系很简单一个主表有多个明细一个明细有多个条件。DAL 层数据访问层代码public static Listfin_voucher_rule_master GetFin_Voucher_Rule_Masters(string name) { using (var db new PcbEntities()) { var q db.fin_voucher_rule_master.AsNoTracking(); if (!string.IsNullOrEmpty(name)) q q.Where(x x.business_type.Contains(name)); return q.ToList(); } }服务层代码转成 JSON 返回给前端public static string GetFin_Voucher_Rule_Masters(string name) { var list DAL.VoucherRuleMasterDAL.GetFin_Voucher_Rule_Masters(name); string json ZhPcb.Common._Json.GetJsonfin_voucher_rule_master(list); json {\total\: list.Count ,\rows\: json }; return json; }看着没啥问题吧结果一跑崩了System.ObjectDisposedException: 此 ObjectContext 实例已释放不可再用于需要连接的操作。刚子第一次遇到的时候也是一脸懵我明明ToList()了数据都查出来了怎么还说“上下文已释放”二、原因分析都是“延迟加载”惹的祸啥是延迟加载简单说EF 默认开启了一个“懒汉模式”你查主表的时候它只把主表自己的字段比如 Id、Name给你。至于主表关联的明细fin_voucher_rule_detail它先不查等你真正用到的时候它再偷偷去数据库查。这个“偷偷查”的动作就叫延迟加载。为啥ToList()之后还会查数据库很多人以为ToList()就万事大吉了数据全在内存里了。错ToList()只加载了你明确查询的那些字段。你没有Include的导航属性EF 不会主动加载。等你一访问它比如 JSON 序列化器想把它转成字符串EF 才反应过来“哎呀这个还没查呢我赶紧去数据库拿。”——结果发现DbContext已经在using外面被释放了于是报错。本案例的执行流程拆解版DAL 层using (var db new PcbEntities())创建数据库连接。执行.AsNoTracking().Where(...).ToList()只加载了主表自身的字段。using块结束db被释放连接关闭。服务层调用 JSON 序列化工具。序列化器很“勤奋”它会递归遍历master对象的所有属性包括导航属性比如fin_voucher_rule_detail。当序列化器访问master.fin_voucher_rule_detail时EF 的代理对象尝试延迟加载——但DbContext已经没了于是抛出ObjectDisposedException。划重点你让 EF 帮你查主表它只给了你主表。你以为完事了结果序列化的时候非要去看明细EF 说“那我再去数据库拿”可数据库连接早就关了。不崩你崩谁三、解决方案三种按需选方案一关掉延迟加载最简单在DbContext里把延迟加载功能关掉。这样 EF 就不会“偷偷”查数据库了访问导航属性只会得到null或空集合不会报错。using (var db new PcbEntities()) { db.Configuration.LazyLoadingEnabled false; // EF6 写法 // 如果是 EF Coredb.ChangeTracker.LazyLoadingEnabled false; var q db.fin_voucher_rule_master.AsNoTracking(); // ... return q.ToList(); }优点改一行代码搞定省心。缺点如果业务上确实需要明细数据你得自己Include。划重点Web 应用一般推荐全局关掉延迟加载然后在需要的地方手动Include。这样最可控。方案二提前加载导航属性Eager Loading用Include和ThenInclude告诉 EF“把明细和条件也一起查出来别偷懒。”EF Core 写法推荐using Microsoft.EntityFrameworkCore; public static Listfin_voucher_rule_master GetFin_Voucher_Rule_Masters(string name) { using (var db new PcbEntities()) { var q db.fin_voucher_rule_master .Include(m m.fin_voucher_rule_detail) .ThenInclude(d d.fin_voucher_rule_condition) .AsNoTracking(); if (!string.IsNullOrEmpty(name)) q q.Where(x x.business_type.Contains(name)); return q.ToList(); } }EF6 写法不支持ThenInclude用字符串或Selectusing System.Data.Entity; public static Listfin_voucher_rule_master GetFin_Voucher_Rule_Masters(string name) { using (var db new PcbEntities()) { var q db.fin_voucher_rule_master .Include(fin_voucher_rule_detail.fin_voucher_rule_condition) .AsNoTracking(); // 或者用 lambda.Include(x x.fin_voucher_rule_detail.Select(d d.fin_voucher_rule_condition)) if (!string.IsNullOrEmpty(name)) q q.Where(x x.business_type.Contains(name)); return q.ToList(); } }优点一次查询把所有需要的数据都拿到性能好。缺点得提前知道要加载哪些导航属性。划重点Include就是“带上明细”ThenInclude就是“再带上明细下面的条件”。EF Core 的写法更直观EF6 稍微别扭点但也能用。方案三用 DTO 投影最专业不直接返回实体而是建一个数据传输对象DTO只放你需要返回的字段。查询的时候直接投影彻底绕过导航属性。public class VoucherRuleMasterDto { public int Id { get; set; } public string BusinessType { get; set; } public ListVoucherRuleDetailDto Details { get; set; } } public static ListVoucherRuleMasterDto GetVoucherRuleMasters(string name) { using (var db new PcbEntities()) { var query db.fin_voucher_rule_master.AsNoTracking(); if (!string.IsNullOrEmpty(name)) query query.Where(x x.business_type.Contains(name)); return query.Select(m new VoucherRuleMasterDto { Id m.Id, BusinessType m.business_type, Details m.fin_voucher_rule_detail.Select(d new VoucherRuleDetailDto { Id d.Id, Condition d.fin_voucher_rule_condition.Description }).ToList() }).ToList(); } }优点只返回前端真正需要的数据网络传输量小。彻底解耦数据库模型和 API 接口。再也不用担心延迟加载和序列化问题。缺点多写几个 DTO 类可以用 AutoMapper 偷懒。划重点DTO 方案是最“正统”的做法推荐在正式项目里用。实体是给数据库用的DTO 是给前端用的别混在一起。四、EF6 和 EF Core 的 Include/ThenInclude 区别一张表看懂很多从 EF6 转到 EF Core 的兄弟会被ThenInclude搞晕。刚子给你总结一下你要加载什么EF6 写法EF Core 写法单个导航属性如 Detail.Include(x x.Detail)或Include(Detail).Include(x x.Detail)嵌套属性Detail.Condition.Include(x x.Detail.Condition)或Include(Detail.Condition).Include(x x.Detail).ThenInclude(d d.Condition)集合的嵌套属性Details里的Condition.Include(x x.Details.Select(d d.Condition)).Include(x x.Details).ThenInclude(d d.Condition)常见坑编译错误Include does not contain a definition for ThenInclude→ 说明你用的是 EF6别用ThenInclude。运行时InvalidOperationException: A second operation started on this context before a previous operation completed→ 你在遍历结果时又触发了延迟加载关掉它或者提前Include。五、最佳实践总结照着做不踩坑Web 应用全局关闭延迟加载在DbContext构造函数里加上public PcbEntities() { this.Configuration.LazyLoadingEnabled false; // EF6 // 或 this.ChangeTracker.LazyLoadingEnabled false; // EF Core }需要关联数据的地方手动Include。只读查询一律用AsNoTracking()提升性能减少内存占用。别在using块外面访问导航属性要么提前Include要么把序列化操作放在using里面。优先用 DTO 投影这是最干净、最专业的做法。搞清楚你的 EF 版本看packages.config或.csprojEntityFramework6.x → EF6Microsoft.EntityFrameworkCore→ EF Core六、完整示例拿来即用以下是一个兼容 EF6 和 EF Core 的写法通过条件编译public static Listfin_voucher_rule_master GetFin_Voucher_Rule_Masters(string name) { using (var db new PcbEntities()) { // 关闭延迟加载 db.Configuration.LazyLoadingEnabled false; var q db.fin_voucher_rule_master.AsNoTracking(); // 预先加载三层数据 #if EF6 q q.Include(fin_voucher_rule_detail.fin_voucher_rule_condition); #else q q.Include(m m.fin_voucher_rule_detail) .ThenInclude(d d.fin_voucher_rule_condition); #endif if (!string.IsNullOrEmpty(name)) q q.Where(x x.business_type.Contains(name)); return q.ToList(); } }最后刚子想说ObjectDisposedException这个错基本每个用 EF 的人都遇到过。搞懂了延迟加载的原理解决起来其实很简单。记住一句话在 DbContext 还活着的时候把你需要的数据全都显式加载好。如果你觉得这篇文章帮你搞明白了点个赞、转给还在被 EF 坑的兄弟。

相关新闻

AI的原理科普:人工智能究竟是如何“思考”的?

AI的原理科普:人工智能究竟是如何“思考”的?

AI的原理科普:人工智能究竟是如何“思考”的?引言:AI真的会思考吗?近年来,ChatGPT、DeepSeek、通义千问、豆包、Kimi等人工智能产品迅速普及,很多人都会产生一个疑问:AI到底是怎么工作的&#x…

2026/9/19 17:14:35 阅读更多 →
六轴机械臂改进混沌麻雀(ISSA)与粒子群算法(PSO)最优时间353轨迹规划对比

六轴机械臂改进混沌麻雀(ISSA)与粒子群算法(PSO)最优时间353轨迹规划对比

✅作者简介:热爱科研的Matlab仿真开发者,擅长毕业设计辅导、数学建模、数据处理、建模仿真、程序设计、完整代码获取、论文复现及科研仿真。🍎 往期回顾关注个人主页:Matlab科研工作室👇 关注我领取海量matlab电子书和…

2026/9/21 23:08:42 阅读更多 →
YOLOv11训练中的AutoAnchor自动锚框计算:何时用、何时不用?

YOLOv11训练中的AutoAnchor自动锚框计算:何时用、何时不用?

别再无脑开启--anchor-tune了!90%的人用错了自动锚框 引言:一个让无数人翻车的参数 先讲一个真实案例。 上个月,一位读者在后台私信我:“用YOLOv11s训练工业零件检测数据集,COCO预训练权重下mAP50有0.52,换到自己的数据集上直接掉到0.31。” 排查了两天,最后发现罪魁祸…

2026/9/18 15:27:33 阅读更多 →

最新新闻

3步搞定应用论文,官方文档太长?这份保姆级教程救急

3步搞定应用论文,官方文档太长?这份保姆级教程救急

3步搞定应用论文,官方文档太长?这份保姆级教程救急 官方文档翻了三遍还是云里雾里?别急,我懂你的痛苦。那些密密麻麻的条款和晦涩术语,确实让人抓不住重点。…

2026/9/22 21:56:17 阅读更多 →
平凡世界读后感手写实现踩坑实录

平凡世界读后感手写实现踩坑实录

平凡世界读后感手写实现踩坑实录 配置环境就卡半天,这种痛谁懂?刚把 Python 环境装好,依赖库没报错,一跑代码直接炸。我为了搞定【平凡世界读后感】的自动化文本分析脚本,折腾了整整两天。网上搜到的方案大多只给结果,不给过程。这次我不藏私,…

2026/9/22 21:56:17 阅读更多 →
赵卯生视角:3个维度拆解新手避坑指南,告别配置环境卡半天

赵卯生视角:3个维度拆解新手避坑指南,告别配置环境卡半天

赵卯生视角:3个维度拆解新手避坑指南,告别配置环境卡半天 配置环境就卡半天?别急,这不仅是你的问题,更是无数新人入行时的共同噩梦。我见过太多同学在 CSDN 上搜了一整天,帖子从 2010 年翻到 2024…

2026/9/22 21:56:17 阅读更多 →
台式电脑推荐速查手册:3个源码细节搞定选型

台式电脑推荐速查手册:3个源码细节搞定选型

台式电脑推荐速查手册:3个源码细节搞定选型 代码复制过来直接报错,变量名对不上,环境版本不兼容,这种场景太常见了。很多开发者在搭建本地环境或推荐配置时,往往陷入“看参数表”的误区,忽略了底层驱动与硬件调度的实际表现。今天这份 速查手册…

2026/9/22 21:56:17 阅读更多 →
搞机器人关节控制别只背公式,看3个实战项目优化代码

搞机器人关节控制别只背公式,看3个实战项目优化代码

搞机器人关节控制别只背公式,看3个实战项目优化代码 面试被问“你的关节控制算法延迟多少?为什么?”答不上来? 很多开发者死记硬背了PD控制或PID参数,但一旦面试官追问“在嵌入式设备上如何降低计算开销”,就哑火了。…

2026/9/22 21:56:17 阅读更多 →
3步搞定南方公园下载:一文搞懂多语言解析差异

3步搞定南方公园下载:一文搞懂多语言解析差异

3步搞定南方公园下载:一文搞懂多语言解析差异 版本升级后 API 全变了,导致你之前写好的脚本直接报错?别慌,这在开发圈太常见了。很多新手面对【南方公园下载】这类资源获取任务时,往往卡在环境配置和接口变动上,其实核心逻辑就那几套。今天咱们不…

2026/9/22 21:55:16 阅读更多 →

日新闻

3台商务办公笔记本实测:手写实现环境配置,告别卡半天

3台商务办公笔记本实测:手写实现环境配置,告别卡半天

3台商务办公笔记本实测:手写实现环境配置,告别卡半天 配置环境就卡半天?别怪机器慢,多半是你没选对工具链。在Java、Go或Python的项目现场, 手写实现…

2026/9/22 0:00:41 阅读更多 →
剑帝加点速查手册:3分钟搞懂核心逻辑

剑帝加点速查手册:3分钟搞懂核心逻辑

剑帝加点速查手册:3分钟搞懂核心逻辑 面试被问原理答不上来,是不是常态?别慌。很多开发者对着 GitHub 开源仓库里的代码发呆,看似简单实则暗藏玄机。今天这份【剑帝加点】速查手册,直接带你拆解核心实现,把面试必考的原理讲透。…

2026/9/22 0:00:41 阅读更多 →
手写实现图片压缩网站核心:搞定WebP转换与质量调优

手写实现图片压缩网站核心:搞定WebP转换与质量调优

手写实现图片压缩网站核心:搞定WebP转换与质量调优 复制来的代码跑不通不知道怎么调?别慌,这种“复制粘贴地狱”在开发圈太常见了。尤其是做 图片压缩网站…

2026/9/22 0:00:41 阅读更多 →

周新闻

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

直接铺开项目本身吧。这几个月我一直在折腾一件事:用Flutter给OpenHarmony做一款游戏集合类的App,说白了就是把若干小游戏塞进一个壳里,用统一入口分发。这个方向本身不算新鲜,真正让我花了不少心思的,是首页那堆游戏卡…

2026/9/22 4:32:41 阅读更多 →
Word表格编号全攻略:从列表编号到题注交叉引用

Word表格编号全攻略:从列表编号到题注交叉引用

写Word文档,最让人头疼的往往是那些“看起来不起眼”的小问题。比如表格编号这事:今天在表后面多加了两个空白行,明天给客户交稿前发现整个章节的编号全部错位,光是挨个改序号就能耗掉大半个下午。我前阵子帮人整理一份上百页的技…

2026/9/22 4:38:57 阅读更多 →
从第一个站到第二个站:独立开发者的静态网站选型与落地实践

从第一个站到第二个站:独立开发者的静态网站选型与落地实践

1. 项目概述1.1 核心需求解析做独立开发者这几年,说实话,第一个网站上线的那天晚上我兴奋得没睡着。但等它跑了半年,流量惨淡、功能臃肿、代码自己都懒得看第二遍之后,我才慢慢琢磨明白一个道理:第一个网站是练手&…

2026/9/22 8:51:04 阅读更多 →

月新闻

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能分类:[AI/大模型]细分主题:AI 增强型 CI/CD 流水线自动化与 GitOps 实践:Agent 工作流、工具调用与任务拆解:从原型到生产的验收清单很多团队在尝试用大…

2026/9/21 15:36:51 阅读更多 →
容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场分类:[工程技术]细分主题:Kubernetes 生产环境运维与排障实战:可复制的项目复盘模板与决策记录大部分团队的事故复盘报告,最后都变成了躺在 Confluence 或钉…

2026/9/21 15:36:51 阅读更多 →
容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步分类:[工程技术]细分主题:Docker 容器化技术与镜像安全管理:核心链路的逐步实现与关键代码取舍面对一个积累了五六年历史包袱的单体架构应用(包含 Web 接口、后台…

2026/9/22 2:43:42 阅读更多 →