0

need you help implementing UnitOfWork for my business layer. Want to wrap multiple different business service calls into a single transaction. Let's assume I use Entity Framework as my repository layer and I have an additional business layer for validation and other business rules. In this example just very very simple.

public class MyDbContext
{
    public DbSet<User> Users;
    public DbSet<Contract> Contracts;
}

public class UserService
{
    public UserService(MyDbContext dbContext)
    {
        _dbContext = dbContext;
    }

    public void AddUser(User user)
    {
        _dbContext.Users.Add(user);
        _dbContext.SaveChanges();
    }
}

public class ContractService
{
    public ContractService(MyDbContext dbContext)
    {
        _dbContext = dbContext;
    }

    public void AddContract(Contract contract)
    {
        _dbContext.Contracts.Add(contract);
        _dbContext.SaveChanges();
    }
}

In my controller:

userService.AddUser(user);
contractService.AddContract(contract);

... The add user calls already save changes but i want to save changes after add contract. So can I do the following?? Or is this somehow bad design?!

Create UnitOfWork class:

public class UnitOfWork
{
    public UnitOfWork(MyDbContext dbContext)
    {
        _dbContext = dbContext;
    }

    public MyDbContext DbContext => _dbContext;

    public void SaveChanges()
    {
        _dbContext.SaveChanges();
    }
}

Change my services to:

public class UserService
{
    public UserService(UnitOfWork unitOfWork)
    {
        _unitOfWork = unitOfWork;
    }

    public void AddUser(User user)
    {
        _unitOfWork.DbContext.Users.Add(user);
    }
}

public class ContractService
{
    public ContractService(UnitOfWork unitOfWork)
    {
        _unitOfWork = unitOfWork;
    }

    public void AddContract(Contract contract)
    {
        _unitOfWork.DbContext.Contracts.Add(contract);
    }
}

And then in my controller I do:

userService.AddUser(user);
contractService.AddContract(contract);
unitOfWork.SaveChanges();

Is this a valid approach?! Really need your help and thoughts on this...

Thanks!!!!

Simon
  • 171
  • 2
  • 11

1 Answers1

0

Your 'UnitOfWork' should contain methods that reflect your use cases. So I would have a method like 'CreateContract' which actually adds the 'user' and 'contract' and commits the transaction and just call this method from the controller.

public void CreateContract(User user,Contract contract)
{
    this.dbContext.Users.Add(user);
    this.dbContext.Contracts.Add(contract);  

    this.dbContext.SaveChanges();
}

This way you can encapsulate any transactional code within this method. Ex - if adding a user and contract are not simply EF calls but calls to different services, you can have a distributed transaction or other code to rollback the transaction.

alwayslearning
  • 4,493
  • 6
  • 35
  • 47
  • Hmmm but I have hundreds of such service call chains that should be executed as single transaction. I cannot add all this methods in a single UnitOfWork class... Okey i could create a UnitOfWork class for different areas but in the end in my web application almost every transaction represents a single webrequest / controller action... This is why i want to call the Commit at the end of a controller action when all service calls were successful... – Simon Aug 31 '16 at 09:42