惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

H
Hackread – Cybersecurity News, Data Breaches, AI and More
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
V
V2EX
T
The Blog of Author Tim Ferriss
腾讯CDC
Hugging Face - Blog
Hugging Face - Blog
雷峰网
雷峰网
爱范儿
爱范儿
GbyAI
GbyAI
H
Help Net Security
I
InfoQ
罗磊的独立博客
酷 壳 – CoolShell
酷 壳 – CoolShell
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
人人都是产品经理
人人都是产品经理
J
Java Code Geeks
Microsoft Security Blog
Microsoft Security Blog
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
N
Netflix TechBlog - Medium
Last Week in AI
Last Week in AI
宝玉的分享
宝玉的分享
云风的 BLOG
云风的 BLOG
Project Zero
Project Zero
P
Privacy & Cybersecurity Law Blog
A
Arctic Wolf
Know Your Adversary
Know Your Adversary
G
Google Developers Blog
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
T
Tor Project blog
V
Vulnerabilities – Threatpost
Y
Y Combinator Blog
WordPress大学
WordPress大学
V
Visual Studio Blog
博客园_首页
G
GRAHAM CLULEY
K
Kaspersky official blog
T
Tailwind CSS Blog
T
Threat Research - Cisco Blogs
博客园 - Franky
D
Docker
Security Latest
Security Latest
I
Intezer
有赞技术团队
有赞技术团队
Application and Cybersecurity Blog
Application and Cybersecurity Blog
博客园 - 【当耐特】
B
Blog RSS Feed
T
The Exploit Database - CXSecurity.com
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻

博客园 - BloggerSb

Swagger 文档设置api版本 .Net Core Routing Demo .net Core读取配置比较 简化版DbExecutor,将DataTable映射到T属性(支持Dapper风格的匿名参数)。(编程题) 大文件单词统计 (编程题) ASP.NET Core CRUD API 创建 UserController,实现 Get, Post, Put, Delete 方法,使用 EF Core 访问数据库。 (编程题) 给定百万级订单表,实现高效分页 + 动态条件查询 + 导出 Excel(避免内存爆炸) (编程题) 实现一个带 CorrelationId、请求日志、异常统一处理的中间件链 (编程题) 异步限流器实现(编程题) 编程题,记录所有接口的执行耗时 .net面试题目 (问答题) 面试高频简答题 Aspose最新Slides破解 HttpContext.User.Identity.IsAuthenticated 为false 关于Cannot resolve scoped service from root provider解决方案 MongoDB用户权限管理,设置密码并连接 mongodb连接字符串 mongodb 使用 MongoDB Compass 创建账号,角色 安装mongodb bootstrap popover 设置悬浮框宽度 div contenteditable="true" 添加placehoder效果 光标自动定位到起始位置contenteditable="true" ,v-html绑定内容,div可编辑时,光标移到最前面
设计模式落地:Repository + UnitOfWork + CQRS 完整实现 (编程题)
BloggerSb · 2026-04-17 · via 博客园 - BloggerSb

设计模式落地:Repository + UnitOfWork + CQRS 完整实现

  Repository(仓储模式):封装数据访问,业务层不直接操作 DB,解耦数据层

  UnitOfWork(工作单元):统一管理事务,保证多仓储操作原子性(要么全成功,要么全回滚)

Project/
├─ Entities/          # 领域实体(数据库映射对象)
├─ Repositories/      # 仓储 + 工作单元
│  ├─ IRepository.cs
│  ├─ Repository.cs
│  ├─ IUnitOfWork.cs
│  └─ UnitOfWork.cs
├─ CQRS/              # CQRS 命令 + 查询
│  ├─ Commands/       # 增删改(写操作)
│  └─ Queries/        # 查询(读操作)
├─ Data/              # 数据库上下文
│  └─ AppDbContext.cs
└─ Services/          # 业务调用层

// Entities/Product.cs
public class Product
{
    public int Id { get; set; }
    public string Name { get; set; }
    public decimal Price { get; set; }
    public int Stock { get; set; }
}
// Data/AppDbContext.cs
using Microsoft.EntityFrameworkCore;

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

    public DbSet<Product> Products => Set<Product>();
}

// Repositories/IRepository.cs
using System.Linq.Expressions;

public interface IRepository<T> where T : class
{
    // 查询
    Task<T> GetByIdAsync(int id);
    Task<List<T>> GetAllAsync();
    Task<List<T>> FindAsync(Expression<Func<T, bool>> predicate);

    // 写入
    Task AddAsync(T entity);
    void Update(T entity);
    void Delete(T entity);
}

// 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;

    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) => 
        await _dbSet.Where(predicate).ToListAsync();

    public async Task AddAsync(T entity) => 
        await _dbSet.AddAsync(entity);

    public void Update(T entity) => 
        _dbSet.Update(entity);

    public void Delete(T entity) => 
        _dbSet.Remove(entity);
}

// Repositories/IUnitOfWork.cs
public interface IUnitOfWork : IDisposable
{
    // 暴露具体仓储
    IRepository<Product> Products { get; }

    // 统一提交事务
    Task<int> SaveChangesAsync();
}

// Repositories/UnitOfWork.cs
public class UnitOfWork : IUnitOfWork
{
    private readonly AppDbContext _dbContext;
    private IRepository<Product> _productRepository;

    public UnitOfWork(AppDbContext dbContext)
    {
        _dbContext = dbContext;
    }

    // 懒加载仓储
    public IRepository<Product> Products
    {
        get => _productRepository ??= new Repository<Product>(_dbContext);
    }

    // 提交事务(所有变更一次性保存)
    public async Task<int> SaveChangesAsync() => 
        await _dbContext.SaveChangesAsync();

    // 释放资源
    public void Dispose() => _dbContext.Dispose();
}

CQRS 核心:查询只读不写,命令只写不改
// CQRS/Queries/GetProductByIdQuery.cs
public class GetProductByIdQuery
{
    private readonly IUnitOfWork _uow;

    public GetProductByIdQuery(IUnitOfWork uow)
    {
        _uow = uow;
    }

    public async Task<Product> ExecuteAsync(int id)
    {
        return await _uow.Products.GetByIdAsync(id);
    }
}
// CQRS/Queries/GetAllProductsQuery.cs
public class GetAllProductsQuery
{
    private readonly IUnitOfWork _uow;

    public GetAllProductsQuery(IUnitOfWork uow)
    {
        _uow = uow;
    }

    public async Task<List<Product>> ExecuteAsync()
    {
        return await _uow.Products.GetAllAsync();
    }
}

// CQRS/Commands/CreateProductCommand.cs
public class CreateProductCommand
{
    private readonly IUnitOfWork _uow;

    public CreateProductCommand(IUnitOfWork uow)
    {
        _uow = uow;
    }

    public async Task ExecuteAsync(Product product)
    {
        await _uow.Products.AddAsync(product);
        await _uow.SaveChangesAsync(); // 提交事务
    }
}

// CQRS/Commands/UpdateProductCommand.cs
public class UpdateProductCommand
{
    private readonly IUnitOfWork _uow;

    public UpdateProductCommand(IUnitOfWork uow)
    {
        _uow = uow;
    }

    public async Task ExecuteAsync(Product product)
    {
        _uow.Products.Update(product);
        await _uow.SaveChangesAsync();
    }
}

// 注册DbContext
builder.Services.AddDbContext<AppDbContext>(options =>
    options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection")));

// 注册 Uow + Repository
builder.Services.AddScoped<IUnitOfWork, UnitOfWork>();

// 注册 CQRS
builder.Services.AddScoped<GetAllProductsQuery>();
builder.Services.AddScoped<GetProductByIdQuery>();
builder.Services.AddScoped<CreateProductCommand>();
builder.Services.AddScoped<UpdateProductCommand>();


[ApiController]
[Route("api/products")]
public class ProductController : ControllerBase
{
    private readonly CreateProductCommand _createCommand;
    private readonly GetProductByIdQuery _getByIdQuery;
    private readonly GetAllProductsQuery _getAllQuery;

    // 构造函数注入
    public ProductController(
        CreateProductCommand createCommand,
        GetProductByIdQuery getByIdQuery,
        GetAllProductsQuery getAllQuery)
    {
        _createCommand = createCommand;
        _getByIdQuery = getByIdQuery;
        _getAllQuery = getAllQuery;
    }

    // 查询(CQRS 读)
    [HttpGet("{id}")]
    public async Task<IActionResult> Get(int id)
    {
        var product = await _getByIdQuery.ExecuteAsync(id);
        return Ok(product);
    }

    // 命令(CQRS 写)
    [HttpPost]
    public async Task<IActionResult> Create(Product product)
    {
        await _createCommand.ExecuteAsync(product);
        return Created("", product);
    }
}

•  查询:Controller → Query → Repository → DB 
•  写入:Controller → Command → UnitOfWork → 多 Repository 统一提交事务 
•  事务保证:多个仓储操作(如新增订单 + 扣库存)只需一次 SaveChangesAsync()