VS调试器在EF Core查询的foreach循环中误显示当前值为null
我之前也碰到过一模一样的情况——遍历EF Core查询返回的列表时,调试器里的循环变量(比如你代码里的foo)显示为null,甚至监视窗口评估它会抛出空引用异常,但实际代码跑起来完全正常,列表里也没有null值,就连刚赋值的临时变量boop都能正常查看。
问题原因
这本质上是EF Core的实体代理(用于延迟加载、变更追踪)和调试器的评估逻辑冲突导致的。调试器在尝试读取循环变量时,会隐式访问实体的一些内部属性或触发代理的延迟加载逻辑,但此时上下文可能处于异步操作后的特殊状态,或者调试器的评估时机和代码执行时机不一致,导致调试器无法正确获取变量值,但实际代码执行时是在上下文的有效生命周期内,访问逻辑是正常的。
解决方法
这里有几个实用的解决办法,按优先级推荐:
临时用
AsNoTracking()禁用追踪/代理
调试的时候,在查询末尾加上.AsNoTracking(),这样EF Core会返回普通的实体对象,而不是动态代理类,调试器就能正常识别循环变量了。注意这只是调试时的临时方案,生产环境如果需要变更追踪或延迟加载,记得恢复:var bar = await context.Bars.Include(b => b.Barlets).AsNoTracking().ToListAsync(); foreach (var foo in bar) { var boop = foo; /*do stuff with foo */ }继续用临时变量查看值
就像你已经做的那样,把循环变量赋值给一个局部临时变量(比如boop),调试时查看这个临时变量。因为临时变量是纯局部变量,不会触发EF代理的额外逻辑,调试器能稳定读取它的值。升级EF Core和调试器版本
这个问题在EF Core 3.x及更早的版本里比较普遍,微软在后续的版本中修复了不少调试相关的兼容性问题。升级到最新的稳定版EF Core,同时确保你的Visual Studio(或其他调试工具)也是最新版本,大概率能彻底解决这个问题。直接监视实体的具体属性
如果不想改代码,也可以不直接监视foo,而是监视它的具体属性,比如foo.Id、foo.Barlets.Count。这样调试器只会访问单个属性,不会触发整个实体的代理逻辑,通常就能正常显示值了。
内容的提问来源于stack exchange,提问作者Kristaps Baumanis

