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
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à Product
và Order
. 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 đó, ProductRepository
và OrderRepository
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ọiCommitAsync
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.
CÔNG TY TNHH GIẢI PHÁP CÔNG NGHỆ TRANG DESIGNER
Trang Designer chuyên thiết kế website chuẩn SEO, thiết kế logo toàn diện giúp doanh nghiệp xây dựng một thương hiệu mạnh và bán hàng hiệu quả trên các nền tảng số cho nhiều lĩnh vực kinh doanh.
Vui lòng liên hệ: 138 Hiền Vương, Phường Phú Thạnh, Quận Tân Phú, TP. Hồ Chí Minh
Điện thoại: 0903.728.335
Website: www.trangdesigner.id.vn