EF和EF Core 的DbContext类实现IDisposable接口。因此,很多最佳编程实践中都建议你将它们放在一个using()块中。不幸的是,至少在Web应用程序中,这样做通常不是一个好主意。
   我与许多从.NET Framework迁移到.NET Core和.NET 5的客户一起工作,其中一些客户在旧版应用程序中并没有使用依赖项注入,或者没有一直使用它。结果导致他们的DbContext类有大量的实例。这样做有很多问题,其中最重要的是它导致了紧耦合。
                  “在Web应用程序中,每个Web请求应该有且只有一个DbContext。”
   如果您遵循上述规则,则一切正常。否则可能会有很多麻烦。比如你会遇到这样的问题:如何跟踪实体,或被跟踪的实体在你认为应保存时并没有保存(稍后对此进行详细介绍)。尤其是如果使用异步代码,你可能会发现DbContext被释放的意外情况,这可能需要一些时间来解决。
                  “在ASP.NET或ASP.NET Core中,配置DbContext最理想的方法是通过DI容器。”
   如果让DI容器(如Autofac)帮你管理DbContext实例及其生命周期,就可以避免以上所有这些麻烦。如果您还使用仓储或类似的抽象,请确保它们的生命周期与DbContext的生命周期一致。ASP.NET Core内置的DI容器和Helper能在Scoped 生命周期类型中为EF Core做出正确的配置。这意味着每个请求将创建一个新的DbContext实例。且这个请求中,任何想使用DbContext实例的操作都共享同一实例。在请求结束时将其清理并释放。如果您使用的是Autofac和EF 6,Scoped就是每个请求只使用一个实例的意思。

using语句和DbContext

使用using语句可能的问题:

  • 您释放了一个DbContext,使得一个实体无法保存
  • 您异步地把DbContext传递给另一个服务,但是在它被(另一个服务)使用前,就在原始服务中的using块中将其释放
  • 当同时当使用构造函数注入并在ConfigureServices 或者 一个Autofac 模块中添加一行代码这种正确的的行为时(即同时使用using和容器管理),整个应用程序范围内显得代码(不必要的)重复和混乱。

多个DbContext的问题

与using语句和DbContext密切相关的问题是:如果有多个DbContext(因为该using语句通常会创建一个新实例)。
                “如果您有多个DbContext尝试使用相同的实体实例,那么您将承受巨大的痛苦。”
   考虑这个简单的示例,它包含了一个Controller和一个service,两者同时在使用dbContext。

假设在Index方法中,从数据库中读取 starship时,它的name属性值为“ Millenium Falcon”。下次访问Index时,name属性值是什么?

SaveChanges()被调用时不执行任何操作。db实例在StarshipService中并未跟踪该实体。所以名称将保持不变。
   那么,我们可以这样解决这个问题。让我们附加实体。这是更新后的service:

再次运行。现在Name的值是什么?

SaveChanges()仍然不执行任何操作。实体的name被更新,该实体依然未跟踪。
   让我们再尝试一次:

现在,它会起作用吗?你觉得如何?

是的,现在name的值已更新为“ Millenium Falcon *”,下次是“ Millenium Falcon **”,等等。

要正确地得到预期的行为,需要进行大量的尝试工作。这段代码是脆弱且重复的,更糟的是,具有隐藏的暂存依赖性。

那么,MVC5/EF6的旧代码中要怎么使用Autofac呢?

安装Nuget软件包

安装Autofac.MVC5 nuget软件包。与.NET Framework nuget包不同,它不会添加一堆类,但你仍然需要将它们连接起来。
   进到global.asax文件中更新Application_Start():

当你成功运行它,你还可以把它们放置到一个模块中,并把它的helper放到在App_Start目录中。

这部分代码中所做的事情有:

  • 配置Autofac的依赖项容器
  • 设置它,以创建controller
  • 设置它,以创建 ApplicationDbContext
  • 设置它,以创建 StarshipService
  • 使用 InstancePerRequest设置上面两个
  • 配置MVC5以使用Autofac来解决其依赖性

这可能也就需要用5分钟。更新之后还会有混乱的代码吗?好了,服务现在看起来像这样:

另外,控制器现在看起来像这样:

请注意,这两种类型现在都遵循显式依赖项原则。同时注意到,在解耦之后的代码没完全没有new关键字,这与显式依赖原则有关。

“方法和类应显式要求(通常通过方法参数或构造函数参数)它们所需要的协作对象才能正常运行。”

不用对所引用对象的隐式依赖感到惊讶。如果需要引用某个类,应该在构造函数中引入它(注:依赖注入)。如果要将类进行解耦,,则应该声明一个抽象类(或接口),而不是直接使用new创建实例或者调用静态方法。

总结

EF和EF Core可以为您节省大量时间,并使你更容易地关注领域模型而不是底层的数据库问题。但是如果没有正确使用它们,当你尝试找出它们出现异常的原因时,它们也会让你很头痛。避免直接实例化和避免using块都将使您的代码更容易使用。对于ASP.NET(Core)应用程序,应确保每个请求有且仅具有一个DbContext实例,而实现此目的的最佳方法是使用诸如Autofac之类的DI容器(或ASP. NET Core内置的 ServiceCollection)。

本文翻译自 https://ardalis.com/avoid-wrapping-dbcontext-in-using/

避免用using包装DbContext【翻译】的更多相关文章

  1. 浅谈 C# Assembly 与 IL (一):C# Assembly 与 Reflection

    作者:Compasslg 前言 前一阵子想利用闲余时间写一个 Unity 游戏的翻译工具,主要是用于翻译一些内嵌在代码中的文本,最初想偷懒看了一下网上的教学推荐说可以先利用DnSpy.ILSpy等工具 ...

  2. 在EntityFramework6中管理DbContext的正确方式——1考虑的关键点(外文翻译)

    (译者注:使用EF开发应用程序的一个难点就在于对其DbContext的生命周期管理,你的管理策略是否能很好的支持上层服务 使用独立事务,使用嵌套事务,并行执行,异步执行等需求? Mehdi El Gu ...

  3. 在EntityFramework6中管理DbContext的正确方式——2DbContext的默认行为(外文翻译)

    (译者注:使用EF开发应用程序的一个难点就在于对其DbContext的生命周期管理,你的管理策略是否能很好的支持上层服务 使用独立事务,使用嵌套事务,并行执行,异步执行等需求? Mehdi El Gu ...

  4. 在EntityFramework6中管理DbContext的正确方式——3环境上下文DbContext vs 显式DbContext vs 注入DbContext(外文翻译)

    (译者注:使用EF开发应用程序的一个难点就在于对其DbContext的生命周期管理,你的管理策略是否能很好的支持上层服务 使用独立事务,使用嵌套事务,并行执行,异步执行等需求? Mehdi El Gu ...

  5. 在EntityFramework6中管理DbContext的正确方式——4DbContextScope:一个简单的,正确的并且灵活的管理DbContext实例的方式(外文翻译)

    (译者注:使用EF开发应用程序的一个难点就在于对其DbContext的生命周期管理,你的管理策略是否能很好的支持上层服务 使用独立事务,使用嵌套事务,并行执行,异步执行等需求? Mehdi El Gu ...

  6. 《Entity Framework 6 Recipes》翻译系列 (1) -----第一章 开始使用实体框架之历史和框架简述

    微软的Entity Framework 受到越来越多人的关注和使用,Entity Framework7.0版本也即将发行.虽然已经开源,可遗憾的是,国内没有关于它的书籍,更不用说好书了,可能是因为EF ...

  7. 《Entity Framework 6 Recipes》中文翻译系列 (11) -----第三章 查询之异步查询

    翻译的初衷以及为什么选择<Entity Framework 6 Recipes>来学习,请看本系列开篇 第三章 查询 前一章,我们展示了常见数据库场景的建模方式,本章将向你展示如何查询实体 ...

  8. 《Entity Framework 6 Recipes》中文翻译系列 (12) -----第三章 查询之使用SQL语句

    翻译的初衷以及为什么选择<Entity Framework 6 Recipes>来学习,请看本系列开篇 3-2使用原生SQL语句更新 问题 你想在实体框架中使用原生的SQL语句,来更新底层 ...

  9. 《Entity Framework 6 Recipes》中文翻译系列 (13) -----第三章 查询之使用Entity SQL

    翻译的初衷以及为什么选择<Entity Framework 6 Recipes>来学习,请看本系列开篇 3-4使用实体SQL查询模型 问题 你想通过执行Entity SQL语句来查询你的实 ...

随机推荐

  1. 阿里云,批量删除oss所有的bucket

    需求:多个账号需要清空bucket.阿里不支持一键删除,很是麻烦. 使用的工具是osscmd,先下载osscmd后解压,然后在同级目录创建两个文件,一个写AccessKeySecret,另一个写Acc ...

  2. 【Azure Redis 缓存】Azure Redis 服务不支持指令CONFIG

    问题描述 在Azure Redis的门户页面中,通过Redis Console连接到Redis后,想通过CONFIG命令来配置Redis,但是系统提示CONFIG命令不能用. 错误消息为:(error ...

  3. [日常摸鱼]bzoj1502[NOI2005]月下柠檬树-简单几何+Simpson法

    关于自适应Simpson法的介绍可以去看我的另一篇blog http://www.lydsy.com/JudgeOnline/problem.php?id=1502 题意:空间里圆心在同一直线上且底面 ...

  4. Appium App UI 自动化测试理论知识

    (一)App自动化测试背景 随着移动终端的普及,手机应用越来越多,也越来越重要.App的回归测试用例数量越来越多,全量回归也越来越消耗时间.另外移动端碎片化严重(碎片化:兼容性测试,手机品牌多样.An ...

  5. HCIP --- BGP综合实验

    实验要求: 实验拓扑: 一.配置IP地址 L:代表环回地址(loop back 0) Y:代表业务网段的地址(loop back 1) 二.因为BGP基于IGP之上,给AS 2内配置OSPF 在R2上 ...

  6. 记一次Ajax请求MVC调优

    问题描述 ASP.NETMVC项目,编辑页面赋值操作,ajax请求很慢. 对同一个控制器有2个请求 一个为获取该表的树形结构数据(绑定下拉框) 一个为获取某实体的单条记录(编辑操作) 排查过程 数据库 ...

  7. Redis基础篇(三)持久化:AOF日志

    Redis是内存数据库,但是一旦服务器宕机,内存中的数据将会全部丢失. 最简单的恢复方式是从后端数据库恢复,但这种方式有两个问题: 频繁访问数据库,会给数据库带来巨大的压力: 从数据库中读取相比从Re ...

  8. 什么是ZooKeeper?ZooKeeper分布式事务详解

    前言 上一章我们了解了zookeeper到底是什么,这一章重点来看zookeeper当初到底面临什么问题? 而zookeeper又是如何解决这些问题的? 实际上zookeeper主要就是解决分布式环境 ...

  9. web项目报错 无法解析,丢失包 是缺少本地运行jre

    1.通过build path 添加add Library 2.添加jre

  10. 算法(Java实现)—— 贪心算法

    贪心算法 应用场景-集合覆盖问题 假设在下面需要付费的广播台,以及广播台新型号可以覆盖的地区,如何选择最少的广播台,让所有地区都可以接收到信号 广播台 覆盖地区 k1 北京.上海.天津 k2 广州.北 ...