在多个服务之间共享 dbcontext 的最佳方式是什么?
What's the best way to share a dbcontext between multiple services?
首先,如果这个问题已经得到解答,我深表歉意。但是我找不到解决方案。
假设我想创建一个订单和一些行,同时创建另一个实体。
服务层:
public class OrderService
{
private DbContext context;
public OrderService()
{
context = new DbContext();
}
public void AddOrder(Order order, List<Orderline> lines, AnotherEntity anotherEntity)
{
context.Orders.Add(order);
context.Orderlines.AddRange(lines);
var anotherService = new AnotherService();
anotherService.AddAnother(anotherEntity)
context.SaveChanges();
}
}
public class AnotherService
{
private DbContext context;
public AnotherService()
{
context = new DbContext();
}
public void AddAnother(AnotherEntity entity)
{
// Maybe some business rules here
context.SomeOtherEntities.Add(entity);
context.SaveChanges();
}
}
控制器:
var orderService = new OrderService();
orderService.Add(order, lines, anotherEntity);
第一个问题是我在两个服务中有不同的上下文,因此有两个不同的事务。我能想到的解决方案:
通过订单服务将 dbcontext 从控制器传递到下一个服务。但这会将上下文暴露给表示层。由于每个服务中的 SaveChanges() 方法,我仍然会有两个事务。我可以通过删除 AddAnother 中的 SaveChanges() 来解决这个问题,但是如果我想独立于表示层调用它怎么办?那样什么都不会保存。
使用 BeginTransaction() 包装 AddOrder 中的代码。但是,如果 AddAnother 调用第三个服务并也使用 BeginTransaction() 怎么办?然后我将以多个嵌套事务结束。
我知道 repository/UOW 模式,甚至尝试实施它,但我看不出它将如何解决这个问题。
我是不是想多了?
最好的方法是在您的服务和整个软件架构中使用 IoC 容器和依赖注入模式。
// Simple example of MVC action method that uses injected context
public IActionResult SomeAction()
{
var s1 = new AnotherService(this.context);
var s2 = new OrderService(this.context);
// call s1 and s2 business logic
this.context.SaveChanges();
}
public class AnotherService
{
private DbContext context;
public AnotherService(DbContext dbcontext)
{
context = dbcontext;
}
public void AddAnother(AnotherEntity entity)
{
// Maybe some business rules here
context.SomeOtherEntities.Add(entity);
}
}
public class OrderService
{
private DbContext context;
public OrderService(DbContext dbcontext)
{
context = dbcontext;
}
public void AddOrder(Order order, List<Orderline> lines, AnotherEntity anotherEntity)
{
context.Orders.Add(order);
context.Orderlines.AddRange(lines);
var anotherService = new AnotherService(context);
anotherService.AddAnother(anotherEntity)
}
}
是的,这是使用注入 DbContext 的简单示例,但您可以深入研究 UoW there
UnitOfWork 在您的服务上创建具有 DbContext 共享实例的层。
由于所有服务都依赖于 UoW 及其上下文,因此您可以提交使用 DbContext 保存数据的 UoW。例如:
// Simple example of MVC action method that uses injected context
public IActionResult SomeAction()
{
using(var uow = new UnitOfWork())
{
var s1 = new AnotherService(uow.Context);
var s2 = new OrderService(uow.Context);
// call s1 and s2 business logic
uow.Commit(); // Commit method implements this.context.SaveChanges(); logic.
}
}
并且在此实现中,您的所有服务都将具有相同的 DbContext 实例。
首先,如果这个问题已经得到解答,我深表歉意。但是我找不到解决方案。
假设我想创建一个订单和一些行,同时创建另一个实体。
服务层:
public class OrderService
{
private DbContext context;
public OrderService()
{
context = new DbContext();
}
public void AddOrder(Order order, List<Orderline> lines, AnotherEntity anotherEntity)
{
context.Orders.Add(order);
context.Orderlines.AddRange(lines);
var anotherService = new AnotherService();
anotherService.AddAnother(anotherEntity)
context.SaveChanges();
}
}
public class AnotherService
{
private DbContext context;
public AnotherService()
{
context = new DbContext();
}
public void AddAnother(AnotherEntity entity)
{
// Maybe some business rules here
context.SomeOtherEntities.Add(entity);
context.SaveChanges();
}
}
控制器:
var orderService = new OrderService();
orderService.Add(order, lines, anotherEntity);
第一个问题是我在两个服务中有不同的上下文,因此有两个不同的事务。我能想到的解决方案:
通过订单服务将 dbcontext 从控制器传递到下一个服务。但这会将上下文暴露给表示层。由于每个服务中的 SaveChanges() 方法,我仍然会有两个事务。我可以通过删除 AddAnother 中的 SaveChanges() 来解决这个问题,但是如果我想独立于表示层调用它怎么办?那样什么都不会保存。
使用 BeginTransaction() 包装 AddOrder 中的代码。但是,如果 AddAnother 调用第三个服务并也使用 BeginTransaction() 怎么办?然后我将以多个嵌套事务结束。
我知道 repository/UOW 模式,甚至尝试实施它,但我看不出它将如何解决这个问题。
我是不是想多了?
最好的方法是在您的服务和整个软件架构中使用 IoC 容器和依赖注入模式。
// Simple example of MVC action method that uses injected context
public IActionResult SomeAction()
{
var s1 = new AnotherService(this.context);
var s2 = new OrderService(this.context);
// call s1 and s2 business logic
this.context.SaveChanges();
}
public class AnotherService
{
private DbContext context;
public AnotherService(DbContext dbcontext)
{
context = dbcontext;
}
public void AddAnother(AnotherEntity entity)
{
// Maybe some business rules here
context.SomeOtherEntities.Add(entity);
}
}
public class OrderService
{
private DbContext context;
public OrderService(DbContext dbcontext)
{
context = dbcontext;
}
public void AddOrder(Order order, List<Orderline> lines, AnotherEntity anotherEntity)
{
context.Orders.Add(order);
context.Orderlines.AddRange(lines);
var anotherService = new AnotherService(context);
anotherService.AddAnother(anotherEntity)
}
}
是的,这是使用注入 DbContext 的简单示例,但您可以深入研究 UoW there
UnitOfWork 在您的服务上创建具有 DbContext 共享实例的层。 由于所有服务都依赖于 UoW 及其上下文,因此您可以提交使用 DbContext 保存数据的 UoW。例如:
// Simple example of MVC action method that uses injected context
public IActionResult SomeAction()
{
using(var uow = new UnitOfWork())
{
var s1 = new AnotherService(uow.Context);
var s2 = new OrderService(uow.Context);
// call s1 and s2 business logic
uow.Commit(); // Commit method implements this.context.SaveChanges(); logic.
}
}
并且在此实现中,您的所有服务都将具有相同的 DbContext 实例。