Trang Designer – Thiết kế website – Mua bán theme giá rẻ, plugin giá rẻ – Dịch vụ thiết kế website giá rẻ chuyên nghiệp chuẩn SEO – Mua bán theme giá rẻ, plugin giá rẻ chính hãng 100% từ nhà cung cấp, hỗ trợ update trọn đời

Trong ASP.NET Core, đặc biệt khi sử dụng Entity Framework Core, đối tượng DbContext đã tự động đóng vai trò của Unit Of Work. Tuy nhiên, để có một cấu trúc rõ ràng, dễ mở rộng và kiểm thử, bạn có thể tạo lớp Unit Of Work riêng kết hợp với các Repository.
Tìm hiểu về Unit Of Work và sử dụng trong ASP.NET Core Web API
Tìm hiểu về Unit Of Work và sử dụng trong ASP.NET Core Web API

Tìm hiểu về Unit Of Work

Unit Of Work là một design pattern giúp quản lý các thay đổi (operations) đối với cơ sở dữ liệu như một đơn vị thống nhất (unit) duy nhất. Mục đích của pattern này là:

  • Đảm bảo tính nhất quán: Tất cả các thao tác thay đổi dữ liệu trong một transaction sẽ được commit cùng lúc. Nếu một thao tác thất bại, toàn bộ transaction có thể được rollback để tránh dữ liệu không nhất quán.
  • Quản lý giao dịch: Unit Of Work đóng vai trò như “điều phối viên” giữa các repository, giúp kiểm soát việc lưu trữ (commit) các thay đổi vào cơ sở dữ liệu.
  • Tách biệt logic nghiệp vụ và truy xuất dữ liệu: Khi kết hợp với Repository pattern, Unit Of Work giúp tách rời các thao tác truy xuất dữ liệu khỏi logic nghiệp vụ, tạo ra một kiến trúc dễ bảo trì và kiểm thử.

Vai trò của Unit Of Work trong ASP.NET Core Web API

Trong ASP.NET Core, đặc biệt khi sử dụng Entity Framework Core, đối tượng DbContext đã tự động đóng vai trò của Unit Of Work. Tuy nhiên, để có một cấu trúc rõ ràng, dễ mở rộng và kiểm thử, bạn có thể tạo lớp Unit Of Work riêng kết hợp với các Repository.
Những lợi ích chính khi sử dụng Unit Of Work:

  • Kiểm soát transaction: Nhiều thao tác trên các repository có thể được gộp lại và commit/rollback cùng lúc.
  • Tăng tính testable: Dễ dàng mock hoặc thay thế Unit Of Work khi viết các bài kiểm thử.
  • Tách biệt các concerns: Phân chia rõ ràng giữa việc quản lý transaction và truy xuất dữ liệu.

Triển khai Unit Of Work kết hợp với Repository

Định nghĩa giao diện IUnitOfWork

Giả sử ta có hai repository cho các entity là ProductOrder. Ta định nghĩa giao diện Unit Of Work như sau:

public interface IUnitOfWork : IDisposable
{
    IProductRepository Products { get; }
    IOrderRepository Orders { get; }
    
    // Commit tất cả các thay đổi trong transaction
    Task<int> CommitAsync();
    
    // Hoặc phương thức đồng bộ nếu cần
    void Commit();
}

Triển khai Unit Of Work

Giả sử bạn sử dụng Entity Framework Core với AppDbContext:

public class UnitOfWork : IUnitOfWork
{
    private readonly AppDbContext _context;
    private IProductRepository _productRepository;
    private IOrderRepository _orderRepository;

    public UnitOfWork(AppDbContext context)
    {
        _context = context;
    }

    // Khởi tạo repository khi lần đầu tiên được yêu cầu
    public IProductRepository Products => 
        _productRepository ??= new ProductRepository(_context);

    public IOrderRepository Orders => 
        _orderRepository ??= new OrderRepository(_context);

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

    public void Commit()
    {
        _context.SaveChanges();
    }

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

Trong đó, ProductRepositoryOrderRepository là các lớp thực thi các giao diện truy xuất dữ liệu tương ứng.
Ví dụ về ProductRepository:

public interface IProductRepository
{
    Task<IEnumerable<Product>> GetAllAsync();
    void Add(Product product);
    // Các phương thức khác (Update, Delete, …)
}

public class ProductRepository : IProductRepository
{
    private readonly AppDbContext _context;
    
    public ProductRepository(AppDbContext context)
    {
        _context = context;
    }
    
    public async Task<IEnumerable<Product>> GetAllAsync()
    {
        return await _context.Products.ToListAsync();
    }
    
    public void Add(Product product)
    {
        _context.Products.Add(product);
    }
    
    // Triển khai các phương thức khác
}

Đăng ký trong Dependency Injection

Trong file Program.cs (hoặc Startup.cs với ASP.NET Core phiên bản cũ hơn), bạn đăng ký IUnitOfWork cùng với AppDbContext:

var builder = WebApplication.CreateBuilder(args);

// Cấu hình DbContext
builder.Services.AddDbContext<AppDbContext>(options =>
    options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection")));

// Đăng ký Unit Of Work
builder.Services.AddScoped<IUnitOfWork, UnitOfWork>();

builder.Services.AddControllers();
var app = builder.Build();

app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();

Sử dụng Unit Of Work trong API Controller

Dưới đây là ví dụ về một controller sử dụng Unit Of Work để thực hiện thao tác CRUD trên Product:

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

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

    // GET: api/Products
    [HttpGet]
    public async Task<IActionResult> GetProducts()
    {
        var products = await _unitOfWork.Products.GetAllAsync();
        return Ok(products);
    }

    // POST: api/Products
    [HttpPost]
    public async Task<IActionResult> PostProduct([FromBody] Product product)
    {
        // Thêm sản phẩm mới qua repository
        _unitOfWork.Products.Add(product);
        
        // Commit tất cả các thay đổi vào cơ sở dữ liệu
        await _unitOfWork.CommitAsync();
        
        return CreatedAtAction(nameof(GetProducts), new { id = product.Id }, product);
    }
    
    // Các endpoint khác (PUT, DELETE, …)
}

Trong ví dụ trên:

  • Controller tiêm IUnitOfWork thông qua Dependency Injection.
  • Khi thêm một sản phẩm mới, thay vì gọi SaveChangesAsync trên DbContext trực tiếp, chúng ta gọi CommitAsync của Unit Of Work, giúp quản lý các thay đổi từ nhiều repository nếu cần.

Ưu điểm của việc sử dụng Unit Of Work

  • Tính nhất quán: Đảm bảo rằng các thao tác trên nhiều repository được commit trong cùng một transaction.
  • Dễ bảo trì: Giúp tách biệt các concern, làm cho code dễ đọc, kiểm thử và bảo trì.
  • Quản lý transaction rõ ràng: Cho phép rollback tất cả các thay đổi nếu một thao tác trong transaction thất bại.

Kết luận

Unit Of Work là một pattern mạnh mẽ giúp quản lý và điều phối các thao tác trên cơ sở dữ liệu, đặc biệt khi cần thực hiện nhiều thao tác cùng một lúc. Khi sử dụng trong ASP.NET Core Web API, bạn có thể kết hợp Unit Of Work với Repository pattern để tạo ra một kiến trúc ứng dụng rõ ràng, dễ bảo trì và kiểm thử. Việc này giúp đảm bảo tính nhất quán dữ liệu, quản lý giao dịch một cách hiệu quả và tách biệt rõ ràng giữa logic nghiệp vụ và truy xuất dữ liệu.

Trả lời

Email của bạn sẽ không được hiển thị công khai. Các trường bắt buộc được đánh dấu *

pzf-icon