在处理DbContext时使用EntityFramework导航属性

Ale*_*ill 3 c# entity-framework idisposable dbcontext

我的Service类(在ASP.NET MVC应用程序中)中的当前检索模式如下所示:

public Client Get(int id)
{
    using (var repo = _repoFactory.Get<Client>())
    {
        return repo.Get(id);
    }
}
Run Code Online (Sandbox Code Playgroud)

_repoFactory.Get<T>()返回贮藏库,配置时,还部署了实体框架DbContext;

但是,当Get(int id)方法的使用者需要在Client对象上使用导航属性时,会抛出异常,因为已经处理了上下文.

我可以预见几种方法来协商这个问题:

  • 不要在服务之外使用导航属性
  • 不要使用延迟加载导航属性
  • 找到一些在请求完成时处理上下文的方法

什么是"正确"(或最不正确)的方式以及如何实现?

Str*_*ior 5

你提出的所有方式都是"正确的",每种方式都有其优点和缺点.您需要决定要使用哪种方法.

不要在服务之外使用导航属性

如果服务返回实体,则难以实施.在我目前的项目中,我们大量使用"DTO",它们是代表我们在给定上下文中需要的数据的新类.因为它们不是实体,所以我们知道它们上的任何属性在从存储库返回之前都将完全水合.

不要使用延迟加载导航属性

这与上面的大致相同,只是您允许某些导航属性可能需要加载.再次,使用这些数据的开发人员如何知道哪些属性可用,哪些属性不可用?"DTO"解决了这个问题,但它们也引入了一堆与现有实体几乎完全相同的额外类.

找到一些在请求完成时处理上下文的方法

通常人们通过在DI框架中将请求范围限制在每​​个请求范围内来实现此目的,并允许DI框架处理其上下文的实例化/处理.

这种方法的主要危险在于,虽然延迟加载属性在访问时不会抛出异常,但每次访问都需要另一个数据库往返.这使得开发人员可以轻松地编写代码,最终只需要两到三次就能完成数千次往返.

但是,如果您有一种可靠的方法来识别性能问题并解决它们,那么您可以在一般情况下使用此方法,然后在您认为有必要时添加一点急切加载.例如,MiniProfiler可以位于您的前端,为您提供有关您正在进行的数据库往返的信息,以及当它注意到许多数据库查询几乎完全相同时的警告.

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