s

UnitofWork in .NetCore


The Unit of Work (UoW) pattern is another design pattern commonly used in conjunction with the Repository pattern, particularly in data-driven applications. It helps manage transactions and ensures that multiple operations across multiple repositories can be committed or rolled back as a single unit. This is particularly useful in scenarios where a series of changes need to be atomic, maintaining data integrity.

Advantages of the Unit of Work Pattern

  1. Transactional Consistency - It ensures that either all operations succeed or none at all, maintaining data integrity.
  2. Centralized Data Access - It provides a single point for managing transactions, making it easier to coordinate changes across multiple repositories.
  3. Reduced Database Round Trips - It can optimize performance by reducing the number of database calls through batch processing.
  4. Easier to Manage Changes - It simplifies the management of changes made to multiple repositories in a single business operation.

Implementing the Unit of Work Pattern in ASP.NET Core

Here’s a step-by-step guide to implementing the Unit of Work pattern alongside the Repository pattern in an ASP.NET Core application.

1. Define the IUnitOfWork Interface

Start by defining an interface for the Unit of Work, which will provide methods to manage repositories and commit changes.

public interface IUnitOfWork : IDisposable
{
    IProductRepository Products { get; }
    ICategoryRepository Categories { get; }
    Task<int> CompleteAsync(); // Saves all changes made in this unit of work
}

2. Implement the Unit of Work Class

Next, create a class that implements the IUnitOfWork interface. This class will manage the repositories and the database context.

public class UnitOfWork : IUnitOfWork
{
    private readonly YourDbContext _context;

    public UnitOfWork(YourDbContext context)
    {
        _context = context;
        Products = new ProductRepository(_context);
        Categories = new CategoryRepository(_context);
    }

    public IProductRepository Products { get; private set; }
    public ICategoryRepository Categories { get; private set; }

    public async Task<int> CompleteAsync()
    {
        return await _context.SaveChangesAsync();
    }

    public void Dispose()
    {
        _context.Dispose();
    }
}

3. Update the Repositories

Make sure your repositories accept a DbContext instance through their constructors so they can share the same context instance managed by the Unit of Work.

public class ProductRepository : IProductRepository
{
    private readonly YourDbContext _context;

    public ProductRepository(YourDbContext context)
    {
        _context = context;
    }

    // Implement repository methods...
}

4. Register Unit of Work in Dependency Injection

In your Program.cs for .NET 8), register the UnitOfWork with the dependency injection container.

services.AddDbContext<YourDbContext>(options =>
        options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));

    services.AddScoped<IUnitOfWork, UnitOfWork>();

    services.AddControllers();

5. Use the Unit of Work in Your Controllers

Finally, use the Unit of Work in your controllers to manage transactions across multiple repositories.

[ApiController]
[Route("api/[controller]")]
public class ProductsController : ControllerBase
{
    private readonly IUnitOfWork _unitOfWork;

    public ProductsController(IUnitOfWork unitOfWork)
    {
        _unitOfWork = unitOfWork;
    }

    [HttpPost]
    public async Task<IActionResult> AddProduct(Product product)
    {
        await _unitOfWork.Products.AddAsync(product);
        await _unitOfWork.CompleteAsync(); // Commit changes

        return CreatedAtAction(nameof(GetById), new { id = product.Id }, product);
    }

    [HttpPut("{id}")]
    public async Task<IActionResult> UpdateProduct(int id, Product product)
    {
        if (id != product.Id)
        {
            return BadRequest();
        }

        await _unitOfWork.Products.UpdateAsync(product);
        await _unitOfWork.CompleteAsync(); // Commit changes

        return NoContent();
    }

    [HttpDelete("{id}")]
    public async Task<IActionResult> DeleteProduct(int id)
    {
        await _unitOfWork.Products.DeleteAsync(id);
        await _unitOfWork.CompleteAsync(); // Commit changes
        return NoContent();
    }
}

The Unit of Work pattern, when combined with the Repository pattern, provides a powerful way to manage data access in ASP.NET Core applications. It helps maintain transactional integrity, centralizes data access logic, and improves code maintainability and testability.


Prev Next

Top Articles

  1. What is JSON
  2. How to convert a javaScript object in JSON object
  3. Some Important JSON Examples
  4. Common JSON Interview Question