1. What is it?
- Implementation of UnitOfWork pattern
- While using the Repository pattern
- Using Entity Framework Core 2.0
2. Features
- UoW is responsible for creating repositories
- Not depending on any specific DbContext, you can create your own
3. How to install
You can find it in the official nuget package server by searching for: WaCore.Data.Ef
4. How to use it
Follow this step-by-step guide to make use of this module or look at the WaCore.Sample
project in the source code.
4.1 Create your own DbContext
For example you create a LibraryDbContext
class, which derives from DbContext
:
public class LibraryDbContext : DbContext
{
public LibraryDbContext(DbContextOptions<LibraryDbContext> options)
: base(options)
{ }
public DbSet<Book> Books { get; set; }
}
4.2 Add WaCore.Data.Ef
module
In your project, which represents the data-layer, add a reference to the module WaCore.Data.Ef
.
4.3 Implement your repository
You create your Repository class by implementing the interface IWacRepository<TEntity>
. Again, there is already an abstract class WacRepository<TEntity, TDbContext
, which implements that interface and uses EF Core 2.0 under the hood.
public class BooksRepository : WacRepository<Book, LibraryDbContext>, IBooksRepository
{
public BooksRepository(LibraryDbContext dbContext) : base(dbContext)
{ }
}
public interface IBooksRepository : IWacRepository<Book>
{
}
4.4 Implement your UnitOfWork
You create your UnitOfWork
class, by implementing the interface IWacUnitOfWork
. You can actually derive from the abstract class WacEfUnitOfWork
, which already implements that interface using EF Core 2.0 under the hood. If you want to use any other ORM, then you just need to implement aforementioned interface.
public class UnitOfWork : WacEfUnitOfWork<LibraryDbContext>, IUnitOfWork
{
public UnitOfWork(LibraryDbContext dbContext, IServiceProvider serviceProvider) : base(dbContext, serviceProvider)
{ }
public IBooksRepository BooksRepository => GetRepository<IBooksRepository>();
}
public interface IUnitOfWork : IWacUnitOfWork
{
IBooksRepository BooksRepository { get; }
}
4.5 Register repositories in IoC container
In the ConfigureServices
method of your Startup
class use the extension method AddUnitOfWork
to register your Unit of Work class and your repositories in the IoC container.
Specify your Unit of Work class in the type parameters of AddUnitOfWork
and add your repositories using the configuration function argument. You can add specific repositories using AddRepository<TRepoInterface, TRepoImplementation>
or all repositories defined in specific assembly using AddRepositoriesFromAssemblyOf<TAssemblySelector>
.
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
var connection = @"Server=(localdb)\mssqllocaldb;Database=WaCore.Sample;Trusted_Connection=True;";
services.AddDbContext<LibraryDbContext>(optionsBuilder =>
optionsBuilder.UseSqlServer(connection));
services.AddUnitOfWork<LibraryDbContext, IUnitOfWork, UnitOfWork>(repoConfig =>
repoConfig.AddRepositoriesFromAssemblyOf<UnitOfWork>());
}
4.6 Use UnitOfWork in your service layer
You can get a UnitOfWork instance using dependency injection via constructor arguments. For instance, you can get an instance in the constructor and then use it as follows in your controller:
[Route("api/[controller]")]
public class BooksController : Controller
{
private IUnitOfWork _unitOfWork;
public BooksController(IUnitOfWork unitOfWork)
{
_unitOfWork = unitOfWork;
}
// POST api/books
[HttpPost]
public async Task<Book> PostAsync([FromBody]Book book)
{
using (var transaction = await _unitOfWork.BeginTransactionAsync())
{
_unitOfWork.BooksRepository.Add(book);
await _unitOfWork.SaveChangesAsync();
transaction.Commit();
}
return book;
}