Triển khai Repository Pattern và Unit of Work trong ASP.NET Core 8

Một trong những vấn đề thường gặp khi code trực tiếp DbContext vào trong Controller là sự phụ thuộc chặt chẽ giữa tầng API và tầng Database. Khi database thay đổi hoặc bạn muốn chuyển sang loại DB khác, bạn sẽ phải sửa code ở khắp mọi nơi.
Để giải quyết vấn đề này, chúng ta sử dụng các mẫu thiết kế (design patterns) để tách biệt các tầng.
Repository Pattern là gì?
Đây là một lớp trung gian giao tiếp với database, che giấu đi sự phức tạp của Entity Framework Core. Controller sẽ không còn biết đến DbContext nữa, mà chỉ giao tiếp thông qua các interface như IProductRepository, IUserRepository.
Hình 1: Tổ chức code theo tầng giúp hệ thống dễ bảo trì hơn.
Tại sao phải có thêm Unit of Work?
Nếu bạn chỉ dùng Repository, mỗi lần gọi SaveAsync() là một lần commit xuống database. Nhưng nếu bạn có một nghiệp vụ phức tạp cần thao tác trên nhiều bảng khác nhau thì sao?
Ví dụ: Xử lý đặt hàng (Order).
- Trừ số lượng tồn kho trong bảng
Products. - Thêm mới một dòng vào bảng
Orders. - Thêm chi tiết vào bảng
OrderDetails.
Nếu bước 1, 2 thành công nhưng bước 3 lỗi, dữ liệu sẽ bị sai lệch.
Hình 2: Unit of Work đảm bảo tính toàn vẹn dữ liệu (Transaction).
Unit of Work sinh ra để giải quyết việc này. Nó đảm bảo tất cả các thao tác trên (thuộc cùng một "đơn vị công việc") phải cùng thành công hoặc cùng thất bại (rollback), đảm bảo tính toàn vẹn của dữ liệu.
