代码之家  ›  专栏  ›  技术社区  ›  Rey

在DbContext实例上有一个俘虏依赖项是否不好?

  •  0
  • Rey  · 技术社区  · 6 年前

    也许这个问题有一些解释,但找不到最好的解决办法:

    blog post 从Mark Seemann关于俘虏依赖性的文章中,据我在文章末尾的理解,他得出结论:永远不要使用或至少尝试避免俘虏依赖性,否则会有麻烦( 到目前为止还可以 ). 这是另一个 post

    他们建议仅通过以下方式使用捕获依赖项: 目的 当你知道你在做什么的时候! ). 这让我想到了我网站上的一个情况。我有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

    控制器中的常规方法如下所示:

    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 Wait以使其成为非阻塞方法的问题。我问这个问题,使用async Wait for dbContext 举个例子,举个例子,我会说:

    public async MyModel GetMyModel()
    {
       var result = //await on a new task which will use dbcontext instance here
       return Mapper.Map<MyModel>(result);
    }
    

    非常感谢您的任何建议!

    2 回复  |  直到 6 年前
        1
  •  1
  •   Adam Simon    6 年前

    我会从远处看这个问题。

    无状态服务层 (所有状态都以DB形式持久化)并符合 一个HTTP请求,一个业务操作 原则(换言之,一个控制器动作一种服务方法)。

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

    在这种情况下,很容易决定选择哪个组件生存期:DbContext和服务类可以是暂时的( 用Autofac术语)或根据请求( InstancePerRequest 俘虏依赖性的问题根本不存在 .

    上述问题的进一步影响:

    • lifetime scopes and IOwned<T> .)

    • EF本身通过以下方式实现工作单元模式 保存更改 这在大多数情况下都适用。实际上,如果UoW over EF的事务处理由于某种原因不能满足您的需求,那么您只需要实现UoW over EF。这些都是相当特殊的情况。

    […]是否存在将async Wait应用于 服务使它们成为非阻塞方法。

    如果您将异步等待模式一直应用到控制器操作(返回 任务<行动结果> 行动结果 async child actions are not supported

        2
  •  0
  •   Ted Elliott    6 年前

    答案总是取决于。。。在以下情况下,此配置可以工作:

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

    我个人建议创建任何依赖于DbContext(直接或间接)的InstancePerRequest。暂时的也可以。您肯定希望一个工作单元中的所有内容都使用相同的DbContext。否则,使用Entity Framework的一级缓存,可能会有不同的服务检索相同的数据库记录,但如果它们不使用相同的DbContext,则会在不同的内存副本上操作。在这种情况下,最后一次更新将获胜。

    我不会在MyService中引用您的容器,只需将其注入。域或业务逻辑中的容器引用应该谨慎使用,并且只能作为最后手段。