.NET MVC+仓储模式+工作单元:18个领域类需多少仓储?
仓储数量的选择:从需求与维护性出发
这个问题其实在.NET MVC结合仓储、工作单元模式的项目里很常见,我来给你拆解下几种常见方案的优劣,再给你实际的建议:
1. 每个需持久化的领域类对应一个仓储
- 优势:完全贴合单一职责原则,每个仓储只专注处理一个实体的CRUD及专属查询逻辑,代码边界清晰。后期修改某个实体的持久化规则时,不会影响其他实体的代码,排查问题也更方便。
- 劣势:如果18个类都单独写,初期会生成较多的仓储接口和实现类。不过.NET里可以用泛型仓储来减少重复代码——先写一个通用的
IRepository<T>和Repository<T>,覆盖大部分基础CRUD操作,只有当某个实体有特殊逻辑时,再继承泛型仓储扩展即可。
2. 按领域包(模块)划分仓储
- 优势:仓储数量直接缩减到5个,适合那些包内领域类关联性极强的场景。比如一个包是「订单模块」,包含订单、订单明细、订单状态类,用一个
OrderModuleRepository统一处理这些类的持久化,能减少类的数量。 - 劣势:如果包内各领域类的业务逻辑差异较大,这个仓储会逐渐变得臃肿,职责模糊。比如修改订单明细的持久化逻辑时,可能不小心影响到订单的代码,后期维护成本会上升。
3. 混合方案:泛型仓储 + 特定实体仓储
这是.NET项目里最常用的折中方案,兼顾复用性和灵活性:
- 先定义通用的泛型仓储接口与实现,覆盖所有实体都需要的基础操作(比如
GetById、Add、Update、GetAll等)。 - 对于有特殊查询或持久化需求的实体,再单独创建对应的仓储接口和实现,继承泛型仓储扩展专属方法。
举个代码示例:
// 泛型仓储接口 public interface IRepository<T> where T : class { T GetById(int id); void Add(T entity); void Update(T entity); void Delete(T entity); IEnumerable<T> GetAll(); } // 泛型仓储实现 public class Repository<T> : IRepository<T> where T : class { protected readonly DbContext _context; public Repository(DbContext context) { _context = context; } // 实现通用CRUD方法... } // 有特殊逻辑的实体仓储(比如用户需要按邮箱查询) public interface IUserRepository : IRepository<User> { User GetByEmail(string email); } public class UserRepository : Repository<User>, IUserRepository { public UserRepository(DbContext context) : base(context) { } public User GetByEmail(string email) { return _context.Set<User>().FirstOrDefault(u => u.Email == email); } }
最终建议:不必纠结形式,优先维护性
其实不用死磕“必须多少个仓储”,核心是选择最符合你项目维护需求的方案:
- 如果大部分领域类都是简单CRUD,用泛型仓储就能覆盖绝大多数场景,只给有特殊逻辑的类单独写仓储,这样仓储数量会远少于18个。
- 如果某个领域包内的类属于同一个聚合(比如订单和订单明细是强关联的聚合根与子实体),可以只为聚合根创建仓储,由聚合根管理子实体的持久化,这也符合DDD的思想。
- 结合工作单元模式时,要确保工作单元能统一管理
DbContext,这样所有仓储的操作才能在同一个事务内生效,这一点比仓储数量的选择更关键。
内容的提问来源于stack exchange,提问作者nuckle
相关产品推荐
相关产品推荐

