深入理解 Repository 模式|.NET Core API 设计最佳实践
作者:xiaoxin.gao · 2025-07-02 · 阅读时间:4分钟
1. 引言 在许多 ASP.NET Core 项目中,你可能会看到控制器(Controller)直接引用 Db […]
1. 引言
在许多 ASP.NET Core 项目中,你可能会看到控制器(Controller)直接引用 DbContext
并写入查询逻辑,导致代码难以维护、难以测试。Repository 模式提供了一种抽象层,将所有与数据库交互的逻辑集中到“仓储”中,实现与业务逻辑层的松耦合。本文用“宝可梦(Pokemon)”示例,带你一步步落地实践。
2. 为什么需要 Repository 模式
- 降低耦合:控制器和业务层只依赖于接口(而非具体实现),便于替换和测试。
- 提高复用:将重复的数据库访问逻辑封装在仓储方法中,避免多处粘贴相同代码。
- 便于单元测试:可对接口打桩(Mock),无需真实数据库即可测试业务逻辑。
3. Repository 模式的两种阐释
3.1 正式定义(学术视角)
Repository 模式旨在为领域与数据映射层之间提供中介,使业务逻辑层无需关注数据存储细节,就像一个“数据库集合”的接口。
3.2 通俗解释(实战视角)
仓储就是一个专门存放“数据库调用”的地方,你把 DbContext
的增删改查都放在这里,需要时在业务或控制器中“即插即用”,就像随时取用一个独立模块。
4. 在 ASP.NET Core 中实现 Repository 模式
4.1 定义模型(Pokemon)
public class Pokemon
{
public int Id { get; set; }
public string Name { get; set; }
// … 其他属性
}
4.2 创建接口(IPokemonRepository)
在 Interfaces/IPokemonRepository.cs
中定义仓储契约:
public interface IPokemonRepository
{
IReadOnlyCollection < Pokemon > GetPokemons();
// 若有增删改查,可继续扩展:
// Pokemon GetPokemon(int id);
// bool CreatePokemon(Pokemon p);
// bool UpdatePokemon(Pokemon p);
// bool DeletePokemon(int id);
}
4.3 编写仓储类(PokemonRepository)
在 Repositories/PokemonRepository.cs
中实现接口:
public class PokemonRepository : IPokemonRepository
{
private readonly AppDbContext _context;
public PokemonRepository(AppDbContext context)
{
_context = context;
}
public IReadOnlyCollection < Pokemon > GetPokemons()
{
// 从 DbContext 中读取所有 Pokemons,并按 Id 排序
return _context.Pokemons
.OrderBy(p = > p.Id)
.ToList();
}
}
要点:
ToList()
明确触发查询,并转换为不可变集合类型。
4.4 在 Controller 中调用仓储方法
在 Controllers/PokemonController.cs
中注入并使用:
[ApiController]
[Route("api/[controller]")]
public class PokemonController : ControllerBase
{
private readonly IPokemonRepository _pokemonRepo;
public PokemonController(IPokemonRepository pokemonRepo)
{
_pokemonRepo = pokemonRepo;
}
[HttpGet]
public ActionResult < IReadOnlyCollection < Pokemon > > GetPokemons()
{
if (!ModelState.IsValid)
return BadRequest(ModelState);
var list = _pokemonRepo.GetPokemons();
return Ok(list);
}
}
- 通过接口注入,对控制器隐藏了具体仓储实现细节。
4.5 配置依赖注入
在 Program.cs
中注册服务:
builder.Services.AddScoped < IPokemonRepository, PokemonRepository > ();
- AddScoped:作用域级别注入,适合每次 HTTP 请求中使用同一实例。
5. 小结与最佳实践
- 接口先行:始终先定义契约接口,再实现类。
- 单一职责:仓储只负责数据访问,不要混入业务逻辑。
- 依赖注入:通过 DI 容器注入接口,解耦控制器与实现。
- 可测试性:在单元测试中对接口打桩,隔离数据库依赖。
- 按需扩展:根据项目需求,为每个实体创建独立仓储,或抽象通用仓储基类。
通过本文示例,你已掌握在 ASP.NET Core 项目中从零搭建 Repository 模式的全流程,让你的 API 更加松耦合、易维护、可测试。继续打磨、优化,项目将更具健壮性与可扩展性!
原文引自YouTube视频:https://www.youtube.com/watch?v=-LAeEQSfOQk
热门推荐
一个账号试用1000+ API
助力AI无缝链接物理世界 · 无需多次注册
3000+提示词助力AI大模型
和专业工程师共享工作效率翻倍的秘密
热门API
- 1. AI文本生成
- 2. AI图片生成_文生图
- 3. AI图片生成_图生图
- 4. AI图像编辑
- 5. AI视频生成_文生视频
- 6. AI视频生成_图生视频
- 7. AI语音合成_文生语音
- 8. AI文本生成(中国)