.NET Core依赖注入下如何复用CRUD通用代码?
.NET Core 中CRUD仓储的代码复用方案
核心思路
通过泛型基类仓储封装通用CRUD逻辑,将重复的Add/Update/Delete代码抽象到泛型类中,仅针对不同实体的特殊逻辑在子类中扩展,彻底消除代码冗余。
步骤1:定义实体通用接口
为所有实体统一主键的访问规范,方便泛型基类处理主键操作:
public interface IEntity<TId> { TId Id { get; set; } }
修改基类ChangeTracker实现该接口(确保所有实体继承它后自动拥有主键属性):
public abstract class ChangeTracker : IEntity<int> { public int Id { get; set; } public string ModifiedBy { get; set; } public byte StatusId { get; set; } }
步骤2:实现泛型基类仓储
创建泛型类CrudRepositoryBase<TModel, TId>,实现ICrudRepository<TModel, TId>接口,封装通用CRUD逻辑:
public class CrudRepositoryBase<TModel, TId> : BaseDao, ICrudRepository<TModel, TId> where TModel : class, IEntity<TId>, ChangeTracker, new() { public CrudRepositoryBase(CustomDbContext dbContext) : base(dbContext) { } public async Task<TModel> AddAsync(TModel model, CancellationToken cancellationToken) { ArgumentNullException.ThrowIfNull(model); var entity = (await CustomDbContext .Set<TModel>() .AddAsync(model, cancellationToken) .ConfigureAwait(false)).Entity; await SaveChangesAsync(cancellationToken).ConfigureAwait(false); return entity; } public async Task DeleteAsync(TId id, string userName, CancellationToken cancellationToken) { var entity = new TModel { Id = id }; CustomDbContext.Set<TModel>().Attach(entity); entity.ModifiedBy = userName; entity.StatusId = (byte)Status.Inactive; await SaveChangesAsync(cancellationToken).ConfigureAwait(false); } public async Task<TModel> UpdateAsync(TModel model, CancellationToken cancellationToken) { ArgumentNullException.ThrowIfNull(model); CustomDbContext.Set<TModel>().Attach(model); await SaveChangesAsync(cancellationToken).ConfigureAwait(false); return model; } }
步骤3:简化具体实体仓储
现在PersonCrudRepository无需重复编写CRUD方法,直接继承泛型基类即可,仅需处理实体专属逻辑:
public class PersonCrudRepository : CrudRepositoryBase<Person, int>, IPersonCrudRepository { public PersonCrudRepository(CustomDbContext dbContext) : base(dbContext) { } // 若Person有特殊业务逻辑(如自定义查询),在此添加即可 }
步骤4:依赖注入注册
直接注册具体仓储,或通过泛型批量注册简化多实体场景:
public virtual void ConfigureServices(IServiceCollection services) { // 注册单个实体仓储 services.AddScoped<IPersonCrudRepository, PersonCrudRepository>(); // 多实体场景下,可批量注册泛型仓储 // services.AddScoped(typeof(ICrudRepository<,>), typeof(CrudRepositoryBase<,>)); }
额外优化建议
- 若实体主键类型不统一,可通过
IEntity<TId>的泛型参数灵活适配,比如IEntity<Guid>。 - 若部分实体需要不同的删除逻辑(如物理删除),可在泛型基类中将
DeleteAsync定义为虚方法,子类重写即可。 - 可将
SaveChangesAsync的调用逻辑抽离,让上层服务决定提交时机,提升事务控制的灵活性。
内容的提问来源于stack exchange,提问作者vcliment89
相关产品推荐
相关产品推荐

