.NET Core 倉(cāng)儲(chǔ)模式(Repository Pattern)的使用教程
倉(cāng)儲(chǔ)模式是領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)(DDD) 和 .NET 項(xiàng)目中最常用的設(shè)計(jì)模式之一,核心作用是隔離業(yè)務(wù)邏輯與數(shù)據(jù)訪(fǎng)問(wèn)層,讓代碼更易維護(hù)、測(cè)試和擴(kuò)展。
一、什么是倉(cāng)儲(chǔ)模式?
核心概念
- 倉(cāng)儲(chǔ)(Repository):充當(dāng)業(yè)務(wù)邏輯和數(shù)據(jù)庫(kù)之間的中介,類(lèi)似內(nèi)存中的集合。
- 作用:業(yè)務(wù)層只調(diào)用倉(cāng)儲(chǔ)方法,不需要關(guān)心數(shù)據(jù)是怎么存/取的(EF Core、Dapper、內(nèi)存都可以)。
- 優(yōu)勢(shì):
- 解耦:數(shù)據(jù)訪(fǎng)問(wèn)邏輯和業(yè)務(wù)邏輯分離
- 可測(cè)試:無(wú)需真實(shí)數(shù)據(jù)庫(kù)即可單元測(cè)試
- 統(tǒng)一數(shù)據(jù)訪(fǎng)問(wèn)規(guī)范,代碼更整潔
- 易于切換數(shù)據(jù)訪(fǎng)問(wèn)技術(shù)(EF Core ↔ Dapper)
標(biāo)準(zhǔn)結(jié)構(gòu)
項(xiàng)目 ├─ Models/Entities // 實(shí)體類(lèi)(對(duì)應(yīng)數(shù)據(jù)庫(kù)表) ├─ Data // 數(shù)據(jù)庫(kù)上下文 ├─ Repositories │ ├─ IRepository.cs // 泛型倉(cāng)儲(chǔ)接口(基礎(chǔ)CRUD) │ ├─ Repository.cs // 泛型倉(cāng)儲(chǔ)實(shí)現(xiàn) │ ├─ IUserRepo.cs // 特定實(shí)體倉(cāng)儲(chǔ)接口 │ └─ UserRepo.cs // 特定實(shí)體倉(cāng)儲(chǔ)實(shí)現(xiàn) └─ Services/Controllers // 調(diào)用倉(cāng)儲(chǔ)
二、快速實(shí)現(xiàn)(.NET Core + EF Core)
1. 準(zhǔn)備工作
安裝 NuGet 包:
Install-Package Microsoft.EntityFrameworkCore Install-Package Microsoft.EntityFrameworkCore.SqlServer
2. 定義實(shí)體(示例:User)
// Entities/User.cs
public class User
{
public int Id { get; set; }
public string Name { get; set; }
public int Age { get; set; }
}
3. 創(chuàng)建數(shù)據(jù)庫(kù)上下文
// Data/AppDbContext.cs
using Microsoft.EntityFrameworkCore;
public class AppDbContext : DbContext
{
public AppDbContext(DbContextOptions<AppDbContext> options) : base(options) { }
public DbSet<User> Users => Set<User>();
}
4. 定義泛型倉(cāng)儲(chǔ)接口(所有實(shí)體通用)
// Repositories/IRepository.cs
using System.Linq.Expressions;
public interface IRepository<T> where T : class
{
// 查詢(xún)
Task<T> GetByIdAsync(int id);
Task<List<T>> GetAllAsync();
Task<List<T>> FindAsync(Expression<Func<T, bool>> predicate);
// 新增/修改/刪除
Task AddAsync(T entity);
Task UpdateAsync(T entity);
Task DeleteAsync(T entity);
// 保存
Task SaveChangesAsync();
}
5. 實(shí)現(xiàn)泛型倉(cāng)儲(chǔ)基類(lèi)
// Repositories/Repository.cs
using Microsoft.EntityFrameworkCore;
using System.Linq.Expressions;
public class Repository<T> : IRepository<T> where T : class
{
protected readonly AppDbContext _dbContext;
private readonly DbSet<T> _dbSet;
// 依賴(lài)注入 DbContext
public Repository(AppDbContext dbContext)
{
_dbContext = dbContext;
_dbSet = _dbContext.Set<T>();
}
public async Task<T> GetByIdAsync(int id) => await _dbSet.FindAsync(id);
public async Task<List<T>> GetAllAsync() => await _dbSet.ToListAsync();
public async Task<List<T>> FindAsync(Expression<Func<T, bool>> predicate)
{
return await _dbSet.Where(predicate).ToListAsync();
}
public async Task AddAsync(T entity) => await _dbSet.AddAsync(entity);
public Task UpdateAsync(T entity)
{
_dbSet.Update(entity);
return Task.CompletedTask;
}
public Task DeleteAsync(T entity)
{
_dbSet.Remove(entity);
return Task.CompletedTask;
}
public async Task SaveChangesAsync() => await _dbContext.SaveChangesAsync();
}
6. 特定實(shí)體倉(cāng)儲(chǔ)(可選,擴(kuò)展通用方法)
// IUserRepository.cs
public interface IUserRepository : IRepository<User>
{
// 擴(kuò)展:根據(jù)姓名查詢(xún)用戶(hù)
Task<User> GetUserByNameAsync(string name);
}
// UserRepository.cs
public class UserRepository : Repository<User>, IUserRepository
{
public UserRepository(AppDbContext dbContext) : base(dbContext) { }
public async Task<User> GetUserByNameAsync(string name)
{
return await _dbContext.Users.FirstOrDefaultAsync(u => u.Name == name);
}
}
7. 注冊(cè)依賴(lài)注入(Program.cs)
// 注冊(cè)數(shù)據(jù)庫(kù)上下文
builder.Services.AddDbContext<AppDbContext>(options =>
options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection")));
// 注冊(cè)泛型倉(cāng)儲(chǔ) + 特定倉(cāng)儲(chǔ)
builder.Services.AddScoped(typeof(IRepository<>), typeof(Repository<>));
builder.Services.AddScoped<IUserRepository, UserRepository>();
8. 在 Controller 中使用倉(cāng)儲(chǔ)
[ApiController]
[Route("api/[controller]")]
public class UserController : ControllerBase
{
private readonly IUserRepository _userRepository;
// 構(gòu)造函數(shù)注入
public UserController(IUserRepository userRepository)
{
_userRepository = userRepository;
}
[HttpGet("{id}")]
public async Task<IActionResult> Get(int id)
{
var user = await _userRepository.GetByIdAsync(id);
return Ok(user);
}
[HttpPost]
public async Task<IActionResult> Add(User user)
{
await _userRepository.AddAsync(user);
await _userRepository.SaveChangesAsync();
return Created("", user);
}
}
三、進(jìn)階:工作單元模式(Unit of Work)
工作單元 + 倉(cāng)儲(chǔ) 是企業(yè)級(jí)開(kāi)發(fā)的最佳組合,解決多倉(cāng)儲(chǔ)事務(wù)統(tǒng)一提交問(wèn)題。
1. IUnitOfWork 接口
public interface IUnitOfWork : IDisposable
{
IUserRepository Users { get; }
Task<int> SaveChangesAsync();
}
2. UnitOfWork 實(shí)現(xiàn)
public class UnitOfWork : IUnitOfWork
{
private readonly AppDbContext _dbContext;
public IUserRepository Users { get; }
public UnitOfWork(AppDbContext dbContext)
{
_dbContext = dbContext;
Users = new UserRepository(_dbContext);
}
public async Task<int> SaveChangesAsync() => await _dbContext.SaveChangesAsync();
public void Dispose() => _dbContext.Dispose();
}
3. 注冊(cè) + 使用
// Program.cs builder.Services.AddScoped<IUnitOfWork, UnitOfWork>(); // Controller private readonly IUnitOfWork _uow; public UserController(IUnitOfWork uow) => _uow = uow; // 調(diào)用 await _uow.Users.AddAsync(user); await _uow.SaveChangesAsync(); // 統(tǒng)一提交
四、倉(cāng)儲(chǔ)模式最佳實(shí)踐
- 不要濫用:簡(jiǎn)單單表操作,直接用泛型倉(cāng)儲(chǔ)即可;復(fù)雜業(yè)務(wù)再建專(zhuān)用倉(cāng)儲(chǔ)。
- IQueryable 慎用:不要在接口返回
IQueryable,會(huì)破壞隔離性,推薦返回List/Task<T>。 - 搭配工作單元:多表操作必須用 UoW 保證事務(wù)一致性。
- 依賴(lài)注入:始終使用 DI 注入倉(cāng)儲(chǔ),不要手動(dòng) new。
- 異步優(yōu)先:.NET Core 全程使用
async/await提升性能。
五、適用場(chǎng)景
- 中大型企業(yè)應(yīng)用
- 需要單元測(cè)試的項(xiàng)目
- 數(shù)據(jù)訪(fǎng)問(wèn)層需要靈活切換(SQL/MySQL/內(nèi)存)
- 多人協(xié)作、規(guī)范統(tǒng)一的項(xiàng)目
總結(jié)
- 倉(cāng)儲(chǔ)模式 = 數(shù)據(jù)訪(fǎng)問(wèn)層封裝,解耦業(yè)務(wù)與數(shù)據(jù)庫(kù)
- 泛型倉(cāng)儲(chǔ)提供通用 CRUD,專(zhuān)用倉(cāng)儲(chǔ)擴(kuò)展個(gè)性化方法
- 工作單元解決多倉(cāng)儲(chǔ)事務(wù)提交問(wèn)題
- .NET Core 中通過(guò)依賴(lài)注入使用,代碼簡(jiǎn)潔易維護(hù)
到此這篇關(guān)于.NET Core 倉(cāng)儲(chǔ)模式(Repository Pattern)的使用教程的文章就介紹到這了,更多相關(guān).NET Core 倉(cāng)儲(chǔ)模式內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
ASP.NET MVC中設(shè)置跨域訪(fǎng)問(wèn)問(wèn)題
這篇文章主要介紹了ASP.NET MVC中設(shè)置跨域訪(fǎng)問(wèn)問(wèn)題,需要的朋友可以參考下2018-06-06
控件開(kāi)發(fā)時(shí)兩種JS嵌入資源方式的使用方法
控件開(kāi)發(fā)時(shí)兩種JS嵌入資源方式的使用方法...2007-04-04
Mvc動(dòng)態(tài)注冊(cè)HttpModule詳解
本文主要介紹了Mvc動(dòng)態(tài)注冊(cè)HttpModule的方法。具有很好的參考價(jià)值,下面跟著小編一起來(lái)看下吧2017-03-03
.NET開(kāi)發(fā)中全局?jǐn)?shù)據(jù)存儲(chǔ)的常見(jiàn)方式
在 .NET 應(yīng)用程序開(kāi)發(fā)中,全局?jǐn)?shù)據(jù)存儲(chǔ)是共享和訪(fǎng)問(wèn)應(yīng)用程序范圍內(nèi)數(shù)據(jù)的常見(jiàn)需求,以下是幾種主要的全局?jǐn)?shù)據(jù)存儲(chǔ)方式及其適用場(chǎng)景、實(shí)現(xiàn)方法和優(yōu)缺點(diǎn)分析2025-06-06
WebForm獲取checkbox選中的值(幾個(gè)簡(jiǎn)單的示例)
WebForm中用checkbox的地方挺多的,下面寫(xiě)了幾個(gè)簡(jiǎn)單的例子,方便以后學(xué)習(xí)使用2014-07-07

