我使用 Entity Framework 已经有一段时间了,我遇到过几个场景,其中两个上下文会尝试访问同一个实体等,所以我想知道我是否没有打开/以最好的方式关闭我的数据库上下文。
目前,我基本上按照最初设置基本 MVC 应用程序的方式在我的每个 Controller 上打开一个 DbContext,这意味着我在 Controller 上有一个私有(private) dbcontext 字段,并且我覆盖了 Controller 的 dispose 方法以在上下文中调用 dispose .
然而,有时我也会在我的其他一些类中对数据库进行查询,这些类可以从 Controller 内部调用, Controller 也有一个打开的上下文。
有没有办法在没有显式处理程序的情况下访问开放上下文?通过十几种不同的方法传递 DbContext 引用对我来说真的没有意义。
最佳答案
使用依赖注入(inject)
正如其他人所说并且可能会重申的那样,“正确的方式”通常被认为是依赖注入(inject)。
在我最近的项目中,我组织了一些事情,所以我几乎完成了项目,DI 非常轻松,以至于我自己做(而不是使用注入(inject)器)。其中一个主要因素是相当严格地遵守这种结构:
WebProject
| |
| DataServices
| | |
ViewModels EntityModels
在一个工作单元期间,通过单个 DataServiceFactory 实例访问所有数据服务,这需要一个 MyDbContext 实例。另一个因素是完全 RESTful 应用程序设计 - 这意味着我不必在我的代码中散布持久性功能。
没有依赖注入(inject)
也就是说,也许 DI 不适合您这个项目。也许:
- 您不打算编写单元测试
- 你需要更多时间来理解 DI
- 您的项目结构已经深度集成了 EF
在 ASP.NET MVC 中,工作单元通常与请求生命周期完全一致 - 即 HttpContext.Current
。因此,您可以根据请求懒惰地实例化存储库“单例”,而不是使用 DI。这是一个经典的单例模式,将当前上下文作为后备存储,用于保存您的 DbContext
:
public class RepositoryProxy {
private static HttpContext Ctx { get { return HttpContext.Current; } }
private static Guid repoGuid = typeof(MyDbContext).GUID;
public static MyDbContext Context {
get {
MyDbContext repo = Ctx.Items[repoGuid];
if (repo == null) {
repo = new MyDbContext();
Ctx.Items[repoGuid] = result;
}
return repo;
}
}
public static void SaveIfContext() {
MyDbContext repo = Ctx.Items[repoGuid];
if (repo != null) repo.SaveChanges();
}
}
如果您觉得特别懒惰,您也可以自动SaveChanges
(您仍然需要手动调用它来检查副作用,当然,比如检索新项目的 id) :
public abstract class ExtendedController : Controller {
protected MyDbContext Context {
get { return RepositoryProxy.Context; }
}
protected override void OnActionExecuted(ActionExecutedContext filterContext) {
RepositoryProxy.SaveIfContext();
base.OnActionExecuted(filterContext);
}
}
关于c# - 如何在没有显式引用的情况下访问打开的 DbContext?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29083548/