为了账号安全,请及时绑定邮箱和手机立即绑定

对 DbContext 实例有强制依赖是不是很糟糕?

对 DbContext 实例有强制依赖是不是很糟糕?

C#
慕标琳琳 2021-11-28 17:52:49
也许这个问题有一些解释,但找不到最好的解决方案:我正在阅读Mark Seemann 的这篇关于强制依赖的博客文章,据我所知,在文章末尾,他得出的结论是永远不要使用或至少尝试避免强制依赖,否则会有麻烦(到目前为止还可以))。这里是另一个职位从Autofac文档。他们建议仅按目的使用俘虏依赖项(当您知道自己在做什么时!)。这让我想到了我在我的网站上遇到的情况。我有 10 个服务,它们都依赖于DbContext数据库操作。我认为它们可以很容易地被注册,就InstancePerLifetimeScope好像我解决了这个问题,DbContext因为它不会永远保存在我的服务附带的内存中。(在我的情况下,我使用的是 Autofac)。所以,我认为一个好的起点是根据生命周期实例和DbContext每个请求创建所有这些实例。然后在我的服务中,我会使用类似的东西:public class MyService{    private readonly IDbContext _dbContext = DependencyResolver.Current.GetService<IDbContext>();    private MyModel GetMyModel() => Mapper.Map<MyModel>(_dbContext.MyTable.FirstOrDefault());}然后在我的启动课程中,我有:builder.RegisterType<ApplicationDbContext>().As<IDbContext>().InstancePerRequest();builder.RegisterType<MyService>().As<IMyService>().InstancePerLifetimeScope();这个模式是否正常工作,我的意思是不将dbContext永远附加到任何服务,所以它将在请求结束时被处理,如果它有效,这一行是否有任何性能问题: private readonly IDbContext _dbContext = DependencyResolver.Current.GetService<IDbContext>();与构造函数注入相比(从 dbContext 到数据库有很多调用,所以IDbContext每次我想使用它时我都害怕,因为它可能会消耗资源)?我想dbContext每个请求都实例化而不是每个依赖项实例化的原因是我已经在dbContext对象之上实现了工作单元模式。我的控制器中的正常方法如下所示:public ActionResult DoSth(){     using(var unitOfWork = UnitOfWorkManager.NewUnitOfWork())     {           //do stuff          try          {              unitOfWork.Commit();              return View();          }          catch(Exception e)          {              unitOfWork.RollBack();              LoggerService.Log(e);              return View();          }     }}如果这工作正常,那么还有一个我担心的问题。因此,如果我可以将我的服务作为每个生命周期的实例(DbContext 除外),那么在服务内部的每个方法上应用 async-await 以使其成为非阻塞方法是否有任何问题。我问这个dbContext实例使用 async-await 是否有任何问题,例如,我会有这样的事情:public async MyModel GetMyModel(){   var result = //await on a new task which will use dbcontext instance here   return Mapper.Map<MyModel>(result);}非常感谢任何建议或建议!
查看完整描述

2 回答

?
LEATH

TA贡献1936条经验 获得超6个赞

我会从远处解决这个问题。

有一些建筑选择可以让您的生活更轻松。在 Web 开发中,将应用程序设计为具有无状态服务层(所有状态都保存在 DB 中)并适合一个 HTTP 请求、一种业务操作原则(换句话说,一种服务方法用于一个控制器操作)是可行的

我不知道你的架构看起来如何(你的帖子中没有足够的信息来确定)但它很可能符合我上面描述的标准。

在这种情况下,可以很容易地决定选择哪一个部件寿命:和的DbContext服务类可短暂(InstancePerDependency在Autofac的术语)或每请求(InstancePerRequest) -这其实并不重要。关键是它们具有相同的生命周期,因此根本不会出现强制依赖的问题

上述内容的进一步含义:

  • 您可以在您的服务类中使用 ctor 注入而无需担心。(无论如何,在调查了生命周期范围和 IOwned<T>生命周期控制可能性之后,服务定位器模式将是最后一个选择。)

  • EF 本身通过适用于大多数情况的SaveChanges实现了工作单元模式。实际上,如果事务处理由于某种原因不能满足您的需要,您只需在 EF 上实现 UoW。这些都是比较特殊的情况。

[...] 在服务内部的每个方法上应用 async-await 以使其成为非阻塞方法是否有任何问题。

如果您始终如一地将 async-await 模式(我的意思是等待所有异步操作)直接应用到您的控制器操作(返回Task<ActionResult>而不是ActionResult),就不会有问题。(但是,请记住,在 ASP.NET MVC 5 中异步支持不完整 -不支持异步子操作。)


查看完整回答
反对 回复 2021-11-28
?
慕容708150

TA贡献1831条经验 获得超4个赞

与往常一样,答案取决于...此配置可以在以下情况下工作:

  1. 您的范围是在请求边界内创建的。您的工作单元是否创建了范围?

  2. 在创建作用域之前,您不解析任何 InstancePerLifetimeScope 服务。否则,如果您在请求中创建多个作用域,它们的寿命可能会比应有的更长。

我个人只建议制作任何依赖于 DbContext(直接或间接)InstancePerRequest 的东西。瞬态也可以。您肯定希望一个工作单元中的所有内容都使用相同的 DbContext。否则,使用实体框架的第一级缓存,您可能有不同的服务来检索相同的数据库记录,但如果它们不使用相同的 DbContext,则会在不同的内存副本上运行。在这种情况下,上次更新将获胜。

我不会在 MyService 中引用你的容器,只是构造函数注入它。域或业务逻辑中的容器引用应该谨慎使用,并且仅作为最后的手段。


查看完整回答
反对 回复 2021-11-28
  • 2 回答
  • 0 关注
  • 185 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信