配置 EF 在访问导航属性未急切加载(且延迟加载已禁用)时抛出异常
我们有一些应用程序当前正在使用启用了延迟加载的 EF 模型。当我关闭延迟加载(以避免隐式加载和我们的大多数 N+1 选择)时,我宁愿访问应该已经热切加载(或在引用上手动 Load() )抛出异常而不是返回 null(因为特定的异常比 null 引用更好、更容易调试)。
我目前倾向于仅修改 t4 模板来执行此操作(因此,如果 reference.IsLoaded == false,则抛出),但想知道这是否已经是一个已解决的问题,无论是在框中还是通过另一个项目。
任何对可以进行源分析并检测此类问题的插件/扩展/等的引用的奖励积分。 :)
We have a few apps that are currently using an EF model that has lazy-loading enabled. When I turn off the lazy-loading (to avoid implicit loads and most of our N+1 selects), I'd much rather have accessing a should-have-been-eager-loaded (or manually Load() on the reference) throw an exception instead of returning null (since a specific exception for this would be nicer and easier to debug than a null ref).
I'm currently leaning towards just modifying the t4 template to do so (so, if reference.IsLoaded == false, throw), but wondered if this was already a solved problem, either in the box or via another project.
Bonus points for any references to plugins/extensions/etc that can do source analysis and detect such problems. :)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
出于几个与性能相关的原因,我想做同样的事情(引发延迟加载) - 我想避免同步查询,因为它们会阻塞线程,并且在某些地方我想避免加载完整的实体,而只是加载属性代码需要的。
仅禁用延迟加载还不够好,因为某些实体具有可以合法为 null 的属性,并且我不想将“null 因为它是 null”与“null 因为我们决定不加载它”混淆。
我还只想选择性地在某些特定的代码路径中启用延迟加载,我知道延迟加载是有问题的。
以下是我的解决方案。
在我的 DbContext 类中,添加此属性:
在代码启动的某个位置,运行以下命令:
ThrowOnSyncQueryInterceptor
的代码如下:然后在使用
AnimalContext
的代码中I wanted to do the same thing (throw on lazy loading) for several performance-related reasons - I wanted to avoid sync queries because they block the thread, and in some places I want to avoid loading a full entity and instead just load the properties that the code needs.
Just disabling lazy loading isn't good enough because some entities have properties that can legitimately be null, and I don't want to confuse "null because it's null" with "null because we decided not to load it".
I also wanted to only optionally throw on lazy loading in some specific code paths where I know lazy loading is problematic.
Below is my solution.
In my DbContext class, add this property:
Somewhere in my code's startup, run this:
The code for
ThrowOnSyncQueryInterceptor
is as follows:Then in the code that uses
AnimalContext
jamesmanning,该项目的创建者 https://github.com/jamesmanning/EntityFramework.LazyLoadLoggingInterceptor ,通过读取堆栈跟踪设法拦截延迟加载的调用。
因此,您可以创建执行以下操作的 DbCommandInterceptor:
我知道读取堆栈跟踪帧可能会很昂贵,尽管我猜测在发生数据访问的正常情况下,与数据访问本身相比,成本可以忽略不计。但是,您需要亲自评估此方法的性能。
(顺便说一句,您所追求的是 NHibernate 多年来拥有的众多出色功能之一)。
jamesmanning, the creator of the project https://github.com/jamesmanning/EntityFramework.LazyLoadLoggingInterceptor, managed to intercept lazy-loaded calls by reading the stack trace.
So in you could create DbCommandInterceptor that does something like:
I know that reading the stack trace frames can be expensive, although my guess would be that in normal circumstances where data access is occurring, the cost is negligible compared to the data access itself. However you will want to assess the performance of this method for yourself.
(As a side note, what you are after is one of the many nice features that NHibernate has had for many many years).
您不必修改 T4。根据提及“T4”,我猜测您正在使用 EDMX。容器的属性窗口具有lazyloadingenabled属性。当您创建新模型时,它被设置为 true。您可以将其更改为 false。 T4 模板将看到这一点并将代码添加到 ctor 中。
此外,如果您使用 Microsoft 的 POCO 模板,他们会将 virtual 关键字添加到您的导航属性中。 virtual+lazyloadingenabled是实现延迟加载的必要组合。如果删除 virtual 关键字,则即使启用了延迟加载,该属性也永远不会延迟加载。
哈
朱莉
You shouldn't have to modify the T4. Based on mention of "T4" I'm guessing you are using EDMX. The properties window of the container has the lazyloadingenabled property. It's set to true when you create a new model. You can change it to false. T4 template will see that and add the code into the ctor.
Also if you're using Microsoft's POCO templates, they'll add the virtual keyword to your nav properties. Virtual + lazyloadingenabled is the necessary combination to get lazy loading. If you remove the virtual keyword then the property will never be lazy loaded, eve if lazyloading is enabled.
hth
julie