在多个服务之间共享dbcontext的最佳方法是什么?

时间:2015-11-01 14:51:38

标签: .net entity-framework dbcontext unit-of-work transactionscope

首先,如果已经回答,我很抱歉。但我无法找到解决方案。

假设我想创建一个订单以及一些行,同时创建另一个实体。

服务层:

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);

第一个问题是我在两个服务中都有不同的上下文,因此有两个不同的事务。我能想到的解决方案:

  1. 将dbcontext从控制器通过订单服务传递到下一个服务。但这会将上下文暴露给表示层。由于每个服务中的SaveChanges()方法,我仍然会有两个事务。我可以通过删除AddAnother中的SaveChanges()来解决这个问题,但如果我想独立于表示层调用它呢?那时什么都不会保存。

  2. 使用BeginTransaction()将代码包装在AddOrder中。但是如果AddAnother调用第三个服务并使用BeginTransaction()呢?然后我将以多个嵌套事务结束。

  3. 我知道存储库/ UOW模式,甚至尝试实现它,但我看不出它将如何解决这个问题。

    我是否过度思考这个?

1 个答案:

答案 0 :(得分:3)

最好的方法是在服务和整个软件架构中使用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实例。