在DbContext被释放时使用EntityFramework导航属性

3

我在ASP.NET MVC应用程序中的Service类中使用的当前检索模式大致如下:

public Client Get(int id)
{
    using (var repo = _repoFactory.Get<Client>())
    {
        return repo.Get(id);
    }
}
_repoFactory.Get<T>()返回一个仓库(repository),当它被释放时,也会释放Entity Framework的DbContext

然而,当Get(int id)方法的调用者需要使用Client对象上的导航属性时,因为上下文已经被释放,所以会抛出异常。
我可以想到几种解决这个问题的方法:
  • 在服务之外不使用导航属性
  • 不使用延迟加载的导航属性
  • 找到其他方式在请求结束时处理上下文的释放
哪种方式是“正确”的(或最不错误的),如何实现?
1个回答

6
你提出的所有方法都是“正确”的,每种方法都有其优缺点。你需要决定要使用哪种方法。
不要在服务外部使用导航属性。
如果服务返回实体,则很难强制执行此操作。在我的当前项目中,我们大量使用“DTO”,这些是表示在给定上下文中需要的数据的新类。因为这些不是实体,所以我们知道它们上的任何属性都将在从存储库返回之前完全加载。
不要使用延迟加载导航属性。
这与上述方法大致相同,只是您允许某些导航属性可能会被急切地加载。再次提问:消费此数据的开发人员如何知道哪些属性可用和不可用?“DTO”解决了这个问题,但它们还引入了一堆与现有实体几乎相同的额外类。
找到其他方法来处理请求结束时的上下文。
通常,人们通过在DI框架中绑定上下文以进行每个请求范围,并允许DI框架负责实例化/处理上下文来完成此操作。
这种方法的主要危险在于,虽然懒加载属性在访问时不会抛出异常,但每次访问都需要进行另一个数据库往返。这使得开发人员很容易意外地编写代码,即使只需要两到三个往返,也会导致进行数千次往返。
但是,如果您有一种可靠的方法来识别性能问题并解决它们,那么您可以在通常情况下使用此方法,然后在必要时添加一些急切加载。例如,MiniProfiler可以坐在您的前端,并为您提供有关您正在进行的数据库往返以及当它注意到许多数据库查询实际上相同时的警告信息。

2
谢谢 - 我觉得我不会得到比这更好的答案了。对于任何遇到这个问题的人,我选择了第三个选项 - 使用Castle Windsor来控制db上下文的生命周期(LifetimePerHttpRequest())。 - Alex

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接