Triển Khai Đơn Vị Công Việc Trong Mẫu Repository Pattern Với C# và Ví Dụ Minh Họa
Trong bài viết này, chúng ta sẽ cùng tìm hiểu chi tiết về cách triển khai Đơn vị Công việc (Unit Of Work) trong Mẫu Repository Pattern bằng ngôn ngữ lập trình C#. Đơn vị Công việc sẽ giúp quản lý các hoạt động CRUD (Tạo, Đọc, Cập nhật, Xóa) trên cơ sở dữ liệu như một giao dịch duy nhất. Điều này có nghĩa rằng nếu một trong các hoạt động không thành công, toàn bộ giao dịch sẽ bị quay lại, đảm bảo tính nhất quán của dữ liệu.
Khái Niệm Repository
Trước tiên, chúng ta cần hiểu về Mẫu Repository. Repository là một lớp được tạo ra để thực hiện các hoạt động cơ sở dữ liệu cho một thực thể nhất định. Chẳng hạn, bạn có thể có một repository cho Thực thể Nhân viên với tất cả các hoạt động CRUD liên quan. Có hai cách triển khai Mẫu Repository:
- Một Repository Cho Mỗi Thực Thể (Không Generic)
- Repository Generic (Một Repository Duy Nhất Cho Tất Cả Thực Thể)
1. Một Repository Cho Mỗi Thực Thể (Không Generic)
Trong mô hình này, bạn sẽ tạo một repository độc lập cho mỗi thực thể trong ứng dụng. Ví dụ: nếu ứng dụng có các thực thể Nhân viên và Khách hàng, cần phải tạo hai repository riêng biệt.
2. Repository Generic
Dùng Repository Generic cho phép bạn có một repository dùng chung cho tất cả các loại thực thể. Điều này giúp tối ưu hóa mã nguồn, giúp bảo trì và mở rộng dễ dàng hơn.
Unit of Work Trong Mẫu Repository Pattern
Mẫu Đơn vị Công việc (Unit of Work) trong C# giúp nhóm các hoạt động (thường là CRUD) vào một giao dịch duy nhất. Nếu một hoạt động nào đó trong giao dịch thất bại, toàn bộ giao dịch sẽ bị hủy bỏ. Ngược lại, nếu tất cả đều thành công, giao dịch sẽ được xác nhận.
Ví Dụ Về Lớp Generic Repository
Dưới đây là một ví dụ về lớp Generic Repository sử dụng Entity Framework:
csharp
using RepositoryUsingEFinMVC.DAL;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
namespace RepositoryUsingEFinMVC.GenericRepository
{
public class GenericRepository<T> : IGenericRepository<T> where T : class
{
public EmployeeDBContext _context = null;
public DbSet<T> table = null;
public GenericRepository()
{
this._context = new EmployeeDBContext();
table = _context.Set<T>();
}
public IEnumerable<T> GetAll()
{
return table.ToList();
}
public T GetById(object id)
{
return table.Find(id);
}
public void Insert(T obj)
{
table.Add(obj);
}
public void Update(T obj)
{
table.Attach(obj);
_context.Entry(obj).State = EntityState.Modified;
}
public void Delete(object id)
{
T existing = table.Find(id);
table.Remove(existing);
}
public void Save()
{
_context.SaveChanges();
}
}
}
Vấn Đề Với Mã Triển Khai Hiện Tại
Khi làm việc với nhiều repositories, mỗi repository sẽ tạo ra và duy trì một phiên bản riêng của DbContext. Điều này có thể gây ra sự không nhất quán trong dữ liệu. Nếu một repository thành công trong việc lưu trữ dữ liệu trong khi một repository khác thất bại, sẽ xảy ra tình trạng mâu thuẫn trong cơ sở dữ liệu.
Giải Pháp: Triển Khai Đơn Vị Công Việc
Để giải quyết vấn đề này, chúng ta cần áp dụng Đơn vị Công việc. Đơn vị Công việc duy trì một phiên bản duy nhất của DbContext và sử dụng nó để thực hiện các hoạt động cho tất cả các repository trong ứng dụng. Điều này đảm bảo rằng mọi hoạt động sẽ được thực hiện trong một giao dịch duy nhất.
Mã Cho Lớp Unit of Work
Dưới đây là mã cho lớp Unit of Work:
csharp
using RepositoryUsingEFinMVC.DAL;
namespace RepositoryUsingEFinMVC.UnitOfWork
{
public class UnitOfWork : IDisposable
{
private EmployeeDBContext _context = new EmployeeDBContext();
private GenericRepository<Employee> employeeRepository;
private GenericRepository<Product> productRepository;
public GenericRepository<Employee> EmployeeRepository
{
get
{
if (this.employeeRepository == null)
this.employeeRepository = new GenericRepository<Employee>(_context);
return employeeRepository;
}
}
public GenericRepository<Product> ProductRepository
{
get
{
if (this.productRepository == null)
this.productRepository = new GenericRepository<Product>(_context);
return productRepository;
}
}
public void Save()
{
_context.SaveChanges();
}
private bool disposed = false;
protected virtual void Dispose(bool disposing)
{
if (!this.disposed)
{
if (disposing)
{
_context.Dispose();
}
}
this.disposed = true;
}
public void Dispose()
{
Dispose(true);
System.GC.SuppressFinalize(this);
}
}
}
Kết Luận
Trong bài viết này, chúng ta đã tìm hiểu về cách triển khai Đơn vị Công việc (Unit Of Work) trong Mẫu Repository Pattern bằng C#. Đơn vị công việc giúp nhóm nhiều hoạt động cơ sở dữ liệu vào một giao dịch duy nhất, đảm bảo tính toàn vẹn và nhất quán cho dữ liệu trong cơ sở dữ liệu.
source: viblo