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!!!!
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.
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.