0
0
Lập trình
Flame Kris
Flame Krisbacodekiller

Hiểu Rõ Về Mẫu Unit Of Work Trong ASP.Net Core

Đăng vào 10 giờ trước

• 5 phút đọc

Giới Thiệu Về Mẫu Unit Of Work

Mẫu Unit Of Work là một mẫu thiết kế dùng để nhóm nhiều thao tác (thường là các gọi đến repository) trong một giao dịch duy nhất. Mẫu này đảm bảo rằng hoặc tất cả các thao tác thành công hoặc không có thao tác nào được áp dụng, từ đó duy trì tính nhất quán của dữ liệu.

Mẫu này thường hoạt động song song với mẫu Repository, mẫu này trừu tượng hóa logic truy cập dữ liệu. Việc kết hợp cả hai mẫu này giúp quản lý các thao tác dữ liệu một cách hiệu quả hơn.

Thiết lập Các Repository Đầu Tiên

Định Nghĩa Các Thực Thể

csharp Copy
// Models/Product.cs
public class Product
{
    public int Id { get; set; }
    public string Name { get; set; }
    public decimal Price { get; set; }
}

// Models/Order.cs
public class Order
{
    public int Id { get; set; }
    public int ProductId { get; set; }
    public DateTime OrderDate { get; set; }
}

// Models/Log.cs
public class Log
{
    public int Id { get; set; }
    public string Message { get; set; }
    public DateTime Timestamp { get; set; }
}

Thiết lập DbContext

csharp Copy
public class AppDbContext : DbContext
{
    public AppDbContext(DbContextOptions<AppDbContext> options) : base(options) {}

    public DbSet<Product> Products { get; set; }
    public DbSet<Order> Orders { get; set; }
    public DbSet<Log> Logs { get; set; }
}

Định Nghĩa Các Repository

csharp Copy
public interface IProductRepository
{
    Task<Product> GetByIdAsync(int id);
    Task AddAsync(Product product);
    void Update(Product product);
    void Delete(Product product);
}

public interface IOrderRepository
{
    Task AddAsync(Order order);
}

public interface ILogRepository
{
    Task AddAsync(Log log);
}

Triển Khai Các Repository

csharp Copy
// Product repositories
public class ProductRepository : IProductRepository
{
    private readonly AppDbContext _context;
    public ProductRepository(AppDbContext context)
    {
        _context = context;
    }

    public async Task<Product> GetByIdAsync(int id)
    {
        return await _context.Products.FindAsync(id);
    }

    public async Task AddAsync(Product product)
    {
        await _context.Products.AddAsync(product);
    }

    public void Update(Product product)
    {
        _context.Products.Update(product);
    }

    public void Delete(Product product)
    {
        _context.Products.Remove(product);
    }
}

public class OrderRepository : IOrderRepository
{
    private readonly AppDbContext _context;
    public OrderRepository(AppDbContext context)
    {
        _context = context;
    }

    public async Task AddAsync(Order order)
    {
        await _context.Orders.AddAsync(order);
    }
}

public class LogRepository : ILogRepository
{
    private readonly AppDbContext _context;
    public LogRepository(AppDbContext context)
    {
        _context = context;
    }

    public async Task AddAsync(Log log)
    {
        await _context.Logs.AddAsync(log);
    }
}

Giao Diện & Triển Khai Mẫu Unit of Work

csharp Copy
public interface IUnitOfWork : IDisposable
{
    IProductRepository Products { get; }
    IOrderRepository Orders { get; }
    ILogRepository Logs { get; }
    Task<int> CompleteAsync();
}

public class UnitOfWork : IUnitOfWork
{
    private readonly AppDbContext _context;

    public IProductRepository Products { get; }
    public IOrderRepository Orders { get; }
    public ILogRepository Logs { get; }

    public UnitOfWork(
        AppDbContext context,
        IProductRepository productRepository,
        IOrderRepository orderRepository,
        ILogRepository logRepository)
    {
        _context = context;
        Products = productRepository;
        Orders = orderRepository;
        Logs = logRepository;
    }

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

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

Tiêm Các Phụ Thuộc

Hãy đảm bảo bạn đăng ký các phụ thuộc với phương thức AddScoped, để tất cả các repository sẽ chia sẻ cùng một instance của DbContext trong một cuộc gọi http cụ thể.

csharp Copy
services.AddDbContext<AppDbContext>(options =>
    options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));

services.AddScoped<IProductRepository, ProductRepository>();
services.AddScoped<IOrderRepository, OrderRepository>();
services.AddScoped<ILogRepository, LogRepository>();
services.AddScoped<IUnitOfWork, UnitOfWork>();

Thực Hiện Trong Controller

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

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

    [HttpPost]
    public async Task<IActionResult> Checkout([FromBody] ProductOrderDto dto)
    {
        var product = new Product { Name = dto.ProductName, Price = dto.Price };
        var order = new Order { ProductId = product.Id, OrderDate = DateTime.UtcNow };
        var log = new Log { Message = "New order placed", Timestamp = DateTime.UtcNow };

        await _unitOfWork.Products.AddAsync(product);
        await _unitOfWork.Orders.AddAsync(order);
        await _unitOfWork.Logs.AddAsync(log);

        // Giao dịch đơn
        await _unitOfWork.CompleteAsync();

        return Ok("Đặt hàng thành công.");
    }
}

Những Điều Cần Lưu Ý

  • Kiểm tra lỗi: Khi thực hiện các thao tác với cơ sở dữ liệu, bạn nên xử lý các ngoại lệ có thể xảy ra để đảm bảo ứng dụng không bị gặp sự cố.
  • Hiệu suất: Đảm bảo rằng các thao tác được thực hiện một cách hiệu quả, đặc biệt trong các giao dịch lớn.

Kết Luận

Chúc mừng bạn! Bạn đã triển khai thành công mẫu Unit Of Work, từ đó giúp bảo vệ cơ sở dữ liệu của bạn khỏi các trạng thái không nhất quán. Hãy thử nghiệm và cho tôi biết nếu bạn có bất kỳ câu hỏi nào. Bạn có thể liên hệ với tôi qua LinkedIn để thảo luận thêm.

Gợi ý câu hỏi phỏng vấn
Không có dữ liệu

Không có dữ liệu

Bài viết được đề xuất
Bài viết cùng tác giả

Bình luận

Chưa có bình luận nào

Chưa có bình luận nào