不同服务之间依赖相同的DbContext实例

问题描述 投票:0回答:2

我正在开发一个遗留的 Asp.Net MVC 5 项目。我们没有合适的数据访问层,我们的业务层类直接与注入的DbContext交互。 我面临一个问题,我在一个简单的例子中抓住了这个问题的本质。

我有类

ServiceA
ServiceB
ServiceC
(我在本示例中省略了接口)。 它们都通过 DI 在构造函数中接收相同的
DbContext
实例。在
ServiceC
中,我想将事务包装在由其他服务执行的多个数据库操作中。这是可行的,因为服务都接收相同的
DbContext
实例。

    public class ServiceC
    {
      public ServiceC(DbContext context, ServiceA serviceA, ServiceB serviceB)
      {
        _context = context;
        _serviceA = serviceA;
        _serviceB = serviceB;
      }
      
      public DoSomething()
      {
        using var transaction = context.Database.BeginTransaction()
        try
        {
          _serviceA.DoSomethingThatInvolvesDbContext1();
          _serviceB.DoSomethingThatInvovlesDbContext2();
          
          transaction.Commit();
        }
        catch
        {
          transaction.Rollback();
          throw;
        }
      }
    }

我看到这个设计的问题是,

ServiceC
的设计方式是这样的,它需要
ServiceA
ServiceB
共享相同的
DbContext
实例。如果我决定以不同的方式配置我的 DI 容器,它就无法工作。 如果实现依赖于特定的 DI 容器配置,这不是一个糟糕的设计吗?

我唯一能想到的就是引入工厂来提供服务:

    public class ServiceC
    {
      public ServiceC(DbContext context, IServiceAFactory serviceA, IServiceBFactory serviceB)
      {
        _context = context;
        _serviceA = serviceAFactory.Get(context);
        _serviceB = serviceBFactory.Get(context);
      }
      
      // Rest of implementation
    }

但这似乎过于复杂..

c# asp.net asp.net-mvc entity-framework dependency-injection
2个回答
0
投票

在不了解整个背景的情况下提出建议有点困难。

从技术上讲,如果您将 DBContext 以及所有 3 个服务注册为 Scoped,那么当您解析第一个服务时,您将向所有服务注入相同的 DBContext 实例。您唯一需要确保的是之前创建一个范围。根据使用情况,这可能已经是正确的。

其他选项是将 DBContext 作为参数传递给服务方法。对我来说,什么是更可靠的解决方案。

或者你可以重构。

您的示例中的手动解析也有效。


0
投票

您应该以对您的应用程序有意义的方式配置您的 DI 服务。

从广义上讲,配置 dbcontexts 的正确方法是将它们构造为

Scoped
依赖项,这意味着您将为每个请求获得 dbcontext 的新实例 但是 同一实例将由内部的所有服务共享请求生命周期。

因此,这里的简单答案是坚持使用范围级别的数据库上下文。 单例/瞬态依赖关系对于数据库上下文没有多大意义。

© www.soinside.com 2019 - 2024. All rights reserved.