为啥在使用实体框架时要重新启动 DbContext?

Posted

技术标签:

【中文标题】为啥在使用实体框架时要重新启动 DbContext?【英文标题】:Why re-initiate the DbContext when using the Entity Framework?为什么在使用实体框架时要重新启动 DbContext? 【发布时间】:2011-10-04 12:31:48 【问题描述】:

我不知道是否有更好的方法来使用DbContext,因为在使用 WCF 时不建议将其设置为静态。所以我们每次要访问数据库时都会创建它。

了解使用实体框架的所有优点后,一些变得毫无用处,因为我们每次都在重新创建DbContext;并且更多可能会导致开销,因为要考虑创建大型实体模型的过程。

你的意见是什么?

【问题讨论】:

是否有人愿意评论将单个实例 DataContext 作为 ref 参数传递给需要针对该特定事务使用它的所有各种方法的想法?这样,不同的对象可以从中添加/删除实体,最后,上下文对象可以在所有修改完成后自行更新。 @Graham:DataContext 仍然跟踪对检索到的“实体”所做的更改,并维护一个身份缓存,以保证检索到的实体多次使用相同的对象实例来表示。它也是轻量级的,并且创建起来并不昂贵。见msdn.microsoft.com/en-us/library/… @Graham:这意味着在您的应用程序生命周期内保留单个实例 DataContext 可能是个坏主意。从我的回答中的文章中:“如果您有一种自然的有限生命周期来管理 ObjectContext,例如短暂的 Form、UnitOfWork 或 Repository,那么相应地确定 ObjectContext 的范围可能是最好的选择。 " 您可以在这里找到创建 DbContext 的成本:***.com/questions/1671334/… 【参考方案1】:

管理生命周期

您是正确的,DbContext 的单个静态实例通常不推荐:

您使用 ObjectContext 的次数越多,它通常就越大。 这是因为它引用了它曾经拥有的所有实体 知道的,基本上是您查询、添加或附加的任何内容。 所以你应该重新考虑无限期地共享同一个 ObjectContext。

这些 cmets 直接应用于 DbContext,因为它包装了 ObjectContext 以公开“简化和更直观的 API。” [see documentation]


建设成本​​

创建上下文的开销相对较低:

现实情况是这个成本实际上相当低,因为主要是它 只涉及通过引用从全局缓存中复制元数据 进入新的 ObjectContext。一般来说,我认为这个成本不值得担心......

使用短期上下文的常用方法是将其包装在 using 块中:

using(DbContext context = new SomeDbContext())

    // Do work with context

为了便于测试,您可能希望您的DbContext 实现一些IDbContext 接口,并创建一个工厂类ContextFactory<T> where T : IDbContext 来实例化上下文。

这使您可以轻松地将任何IDbContext 交换到您的代码中(即object mocking 的内存中上下文。)


资源

MSDN: How to decide on a lifetime for your ObjectContext ***: Instantiating a context in LINQ to Entities

【讨论】:

感谢您提供更多信息。那么,在这种情况下我们应该使用 EF 吗?例如,ADO.net 可以处理基本的数据库功能。还是因为我们可以从 EF 获得的开发速度? 从技术上讲,EF 是 ADO.NET 的一部分,尽管它是 ORM 的附加抽象层。由于强类型和 LINQ,我个人喜欢在 EF 工作。我认为经典数据集的灵活性要差得多。另见:***.com/questions/5268546/… “为了便于测试,您可能希望您的 DbContext 实现一些 IDbContext 接口” - 我倾向于这个方向。感谢您的确认。 对于使用 AddDbContext 和 DI 的人,您可以从 host.Services.CreateScope() 方法中获益。默认情况下 DbContext 是 Scoped 的,因此如果您使用的不是 WebApp(例如 WebJob),只需创建一个新范围并从那里获取 DB 上下文。每次创建新范围时都会有一个新范围。【参考方案2】:

Web 开发的最佳实践似乎是“每个 Web 请求一个上下文”,请参阅 Proper Session/DbContext lifecycle management,在使用 WCF 时,可以将每个操作转换为一个上下文(即每个 WCF 一个上下文方法调用)。

有不同的方法可以实现这一点,但一种可能由于不同原因不推荐的解决方案是创建上下文的新实例并将其传递给业务类的构造函数:

public void WCFMethod()

  using (DBContext db = new DBContext())
  
    BusinessLogic logic = new BusinessLogic(db);
    logic.DoWork();
  

【讨论】:

以上是关于为啥在使用实体框架时要重新启动 DbContext?的主要内容,如果未能解决你的问题,请参考以下文章

如何刷新实体框架核心 DBContext?

实体框架核心 DbContext 和依赖注入

实体框架 4.1 DbSet 重新加载

实体框架 DbContext 执行的日志查询

实体框架 CTP5 重新加载相关实体

实体框架:如何防止 dbcontext 被多个线程访问?