我正在开发一个遗留的 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
}
但这似乎过于复杂..
在不了解整个背景的情况下提出建议有点困难。
从技术上讲,如果您将 DBContext 以及所有 3 个服务注册为 Scoped,那么当您解析第一个服务时,您将向所有服务注入相同的 DBContext 实例。您唯一需要确保的是之前创建一个范围。根据使用情况,这可能已经是正确的。
其他选项是将 DBContext 作为参数传递给服务方法。对我来说,什么是更可靠的解决方案。
或者你可以重构。
您的示例中的手动解析也有效。