一起聊聊 C# 中的工作單元模式
工作單元(Unit of Work, UoW)模式是一種用于處理事務(wù)性工作的方法,特別適用于需要對數(shù)據(jù)庫進(jìn)行多次操作時(shí)。它的主要目的是將多個(gè)數(shù)據(jù)庫操作封裝在一個(gè)事務(wù)中,確保所有操作能整體成功或者整體失敗,從而保證數(shù)據(jù)的一致性。
本文將詳細(xì)介紹如何在 C# 中實(shí)現(xiàn)工作單元模式,并提供完整的代碼注釋。
工作單元模式的關(guān)鍵概念
- 工作單元(Unit of Work):一個(gè)類,它封裝了一個(gè)業(yè)務(wù)事務(wù)的多個(gè)操作,并記錄對這些操作的更改。
- 倉儲(Repository):一個(gè)類,它管理實(shí)體的持久化,并通常與工作單元合作。
- 事務(wù)管理:確保多次數(shù)據(jù)庫操作要么全部成功,要么全部回滾。
實(shí)現(xiàn)步驟
下面是實(shí)現(xiàn)工作單元模式的步驟:
- 定義實(shí)體類。
- 定義倉儲接口和實(shí)現(xiàn)。
- 定義工作單元接口和實(shí)現(xiàn)。
- 使用工作單元及其倉儲。
1. 定義實(shí)體類
首先,我們定義一個(gè)簡單的實(shí)體類 Product。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AppUnitWork
{
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
}
}
2. 定義倉儲接口和實(shí)現(xiàn)
接下來,定義各種實(shí)體的倉儲接口和實(shí)現(xiàn)。這里以 Product 為例。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AppUnitWork
{
public interface IProductRepository
{
IEnumerable<Product> GetAll();
Product GetById(int id);
void Add(Product product);
void Update(Product product);
void Delete(int id);
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AppUnitWork
{
public class ProductRepository : IProductRepository
{
private readonly AppDbContext _context;
public ProductRepository(AppDbContext context)
{
_context = context;
}
public IEnumerable<Product> GetAll() => _context.Products.ToList();
public Product GetById(int id) => _context.Products.Find(id);
public void Add(Product product)
{
_context.Products.Add(product);
}
public void Update(Product product)
{
_context.Products.Update(product);
}
public void Delete(int id)
{
var product = _context.Products.Find(id);
if (product != null)
{
_context.Products.Remove(product);
}
}
}
}
3. 定義工作單元接口和實(shí)現(xiàn)
定義工作單元以管理多個(gè)倉儲和事務(wù)。
public interface IUnitOfWork : IDisposable
{
IProductRepository Products { get; }
int Complete();
}
public class UnitOfWork : IUnitOfWork
{
private readonly AppDbContext _context;
public IProductRepository Products { get; private set; }
public UnitOfWork(AppDbContext context, IProductRepository productRepository)
{
_context = context;
Products = productRepository;
}
public int Complete()
{
return _context.SaveChanges();
}
public void Dispose()
{
_context.Dispose();
}
}
4. 使用工作單元及其倉儲
示例調(diào)用代碼展示了如何使用工作單元和倉儲來實(shí)現(xiàn)多個(gè)數(shù)據(jù)庫操作的事務(wù)管理。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AppUnitWork
{
public class ProductService
{
private readonly IUnitOfWork _unitOfWork;
public ProductService(IUnitOfWork unitOfWork)
{
_unitOfWork = unitOfWork;
}
public void PerformProductOperations()
{
// 增加新產(chǎn)品
var newProduct = new Product { Name = "New Product", Price = 99.99m };
_unitOfWork.Products.Add(newProduct);
_unitOfWork.Complete();
Console.WriteLine("Added new product");
// 更新現(xiàn)有產(chǎn)品
var product = _unitOfWork.Products.GetById(1);
if (product != null)
{
product.Price = 79.99m;
_unitOfWork.Products.Update(product);
_unitOfWork.Complete();
Console.WriteLine("Updated existing product");
}
// 刪除產(chǎn)品
_unitOfWork.Products.Delete(2);
_unitOfWork.Complete();
Console.WriteLine("Deleted product");
}
}
}
5. AppDbContext 類
確保你已經(jīng)添加了 Microsoft.EntityFrameworkCore 和 Microsoft.EntityFrameworkCore.InMemory 包。這可以通過 NuGet 包管理器或者在命令行中執(zhí)行以下命令來完成:
dotnet add package Microsoft.EntityFrameworkCore
dotnet add package Microsoft.EntityFrameworkCore.InMemory
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AppUnitWork
{
public class AppDbContext : DbContext
{
public DbSet<Product> Products { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
// 配置使用內(nèi)存數(shù)據(jù)庫
optionsBuilder.UseInMemoryDatabase("InMemoryDb");
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
// 通過種子數(shù)據(jù)來預(yù)填充內(nèi)存數(shù)據(jù)庫
modelBuilder.Entity<Product>().HasData(
new Product { Id = 1, Name = "Product 1", Price = 10.00m },
new Product { Id = 2, Name = "Product 2", Price = 20.00m }
);
}
}
}
5. 調(diào)用
using Microsoft.Extensions.DependencyInjection;
using System;
namespace AppUnitWork
{
internal class Program
{
static void Main(string[] args)
{
// 設(shè)置依賴注入
var serviceProvider = new ServiceCollection()
.AddDbContext<AppDbContext>()
.AddScoped<IProductRepository, ProductRepository>()
.AddScoped<IUnitOfWork, UnitOfWork>()
.AddScoped<ProductService>()
.BuildServiceProvider();
using (var scope = serviceProvider.CreateScope())
{
var productService = scope.ServiceProvider.GetRequiredService<ProductService>();
productService.PerformProductOperations();
DisplayAllProducts(scope.ServiceProvider.GetRequiredService<IUnitOfWork>());
}
}
static void DisplayAllProducts(IUnitOfWork unitOfWork)
{
var products = unitOfWork.Products.GetAll();
foreach (var product in products)
{
Console.WriteLine($"Product Id: {product.Id}, Name: {product.Name}, Price: {product.Price}");
}
}
}
}
圖片
總結(jié)
通過應(yīng)用工作單元模式,我們能夠確保多個(gè)數(shù)據(jù)庫操作的事務(wù)性,這在進(jìn)行復(fù)雜的業(yè)務(wù)邏輯和數(shù)據(jù)操作時(shí)尤為重要。本文介紹了工作單元模式的基本概念和實(shí)現(xiàn)步驟,附帶具體的代碼示例,希望對你有所幫助。