简单整理一下仓储层。
正文在共享层的基础建设类库中:
/// <summary> /// 泛型仓储接口 /// </summary> /// <typeparam name="TEntity">实体类型</typeparam> public interface IRepository<TEntity> where TEntity : Entity, IAggregateRoot { IUnitOfWork UnitOfWork { get; } TEntity Add(TEntity entity); Task<TEntity> AddAsync(TEntity entity, CancellationToken cancellationToken = default); TEntity Update(TEntity entity); Task<TEntity> UpdateAsync(TEntity entity, CancellationToken cancellationToken = default); // 当前接口未指定主键类型,所以这里需要根据实体对象去删除 bool Remove(Entity entity); Task<bool> RemoveAsync(Entity entity); } /// <summary> /// 泛型仓储接口 /// </summary> /// <typeparam name="TEntity">实体类型</typeparam> /// <typeparam name="TKey">主键Id类型</typeparam> public interface IRepository<TEntity, TKey> : IRepository<TEntity> where TEntity : Entity<TKey>, IAggregateRoot { bool Delete(TKey id); Task<bool> DeleteAsync(TKey id, CancellationToken cancellationToken = default); TEntity Get(TKey id); Task<TEntity> GetAsync(TKey id, CancellationToken cancellationToken = default); }IRepository 是定义了一个接口,表示要实现增删改查方法。
同样在该类库下,创建了对应的实现。
之所以在相同类库中建立实现的原因,就是因为没有必要分为两个类库。
以前我们写三层的时候分为IDAL 类库和 DAL 类库。IDAl 是接口层,DAL 是具体的实现。他们就称为DataAccessLayer层,也就是数据访问层。
然后用的时候发现一个问题,那就是数据库非常的稳定,哪家公司没事会去换数据库呢?
然后就把DAl类库和IDAL类库合并到DAl类库,然后把接口写在DAl类库,新建一个文件夹,叫做IDAl文件夹,里面放置接口。
如果到时候部分迁移到另外的数据库,又可以把接口移出来,新建类库进行重写这部分。
同样的现在微服务,每个应用都比较小,那么DAl可能就那么几个类,同样类中实现的方法也就那么几个,然后可能就把接口和类写在同一个cs里面。
当然这种是因为是数据库不会换,会有这种演变。如果是扩展性比较强的,比如依赖注入,那么还是要把接口和实现分开。
上面这个只是个人理解,如有错误望请指点。
实现如下:
/// <summary> /// 泛型仓储抽象基类 /// </summary> /// <typeparam name="TEntity">实体类型</typeparam> /// <typeparam name="TDbContext">EFContext实例</typeparam> public abstract class Repository<TEntity, TDbContext> : IRepository<TEntity> where TEntity : Entity, IAggregateRoot where TDbContext : EFContext { protected virtual TDbContext DbContext { get; set; } public Repository(TDbContext dbContext) { DbContext = dbContext; } /// <summary> /// 工作单元 /// 因为 EFContext 实现了 IUnitOfWork,所以这里直接返回 EFContext 的实例即可 /// </summary> public IUnitOfWork UnitOfWork => DbContext; public virtual TEntity Add(TEntity entity) { return DbContext.Add(entity).Entity; } public virtual Task<TEntity> AddAsync(TEntity entity, CancellationToken cancellationToken = default) { return Task.FromResult(Add(entity)); } public virtual TEntity Update(TEntity entity) { return DbContext.Update(entity).Entity; } public virtual Task<TEntity> UpdateAsync(TEntity entity, CancellationToken cancellationToken = default) { return Task.FromResult(Update(entity)); } public bool Remove(Entity entity) { DbContext.Remove(entity); return true; } public Task<bool> RemoveAsync(Entity entity) { return Task.FromResult(Remove(entity)); } } /// <summary> /// 泛型仓储抽象基类 /// </summary> /// <typeparam name="TEntity">实体类型</typeparam> /// <typeparam name="TKey">主键Id类型</typeparam> /// <typeparam name="TDbContext">EFContext实例</typeparam> public abstract class Repository<TEntity, TKey, TDbContext> : Repository<TEntity, TDbContext>, IRepository<TEntity, TKey> where TEntity : Entity<TKey>, IAggregateRoot where TDbContext : EFContext { public Repository(TDbContext dbContext) : base(dbContext) { } public virtual bool Delete(TKey id) { var entity = DbContext.Find<TEntity>(id); if (entity == null) { return false; } DbContext.Remove(entity); return true; } public virtual async Task<bool> DeleteAsync(TKey id, CancellationToken cancellationToken = default) { var entity = await DbContext.FindAsync<TEntity>(id, cancellationToken); if (entity == null) { return false; } DbContext.Remove(entity); return true; } public virtual TEntity Get(TKey id) { return DbContext.Find<TEntity>(id); } public virtual async Task<TEntity> GetAsync(TKey id, CancellationToken cancellationToken = default) { return await DbContext.FindAsync<TEntity>(id, cancellationToken); } }然后到了基础建设层,也就是具体实现层,我们需要注入模型与数据库的映射关系:
/// <summary> /// EFContext具体实现 /// </summary> public class DomainContext : EFContext { public DomainContext( DbContextOptions options,IMediator mediator,ICapPublisher capBus) :base(options,mediator,capBus) { } public DbSet<Order> Orders { get; set; } public DbSet<User> Users { get; set; } protected override void OnModelCreating(ModelBuilder modelBuilder) { #region 注册领域模型与数据库的映射关系 modelBuilder.ApplyConfiguration(new OrderEntityTypeConfiguration()); modelBuilder.ApplyConfiguration(new UserEntityTypeConfiguration()); #endregion base.OnModelCreating(modelBuilder); } }这里我随便找一个模型的应用配置看下,看下order的。
/// <summary> /// 领域模型 Order 数据库映射配置 /// </summary> class OrderEntityTypeConfiguration : IEntityTypeConfiguration<Order> { public void Configure(EntityTypeBuilder<Order> builder) { // 定义主键 builder.HasKey(p => p.Id); // 指定表名 builder.ToTable("Order"); // 设置字段长度限制 builder.Property(p => p.UserId).HasMaxLength(20); builder.Property(p => p.UserName).HasMaxLength(30); // 导航属性 builder.OwnsOne(c => c.Address, a => { a.WithOwner(); a.Property(p => p.City).HasMaxLength(20); a.Property(p => p.Street).HasMaxLength(50); a.Property(p => p.ZipCode).HasMaxLength(10); }); } }定义了一些主键、表名、设置字段长度限制、导航属性。
对了,如果你们的数据库很稳定,且多个应用都用到了这些表,那么也可以将这些剥离到一个类库中共享。
因为我们的事务是工作单元模式,那么事务的处理是独立开来的,那么看下在基础建设层,事务的处理如下(这个在后面的使用中会具体介绍):
/// <summary> /// 数据库上下文事务处理 /// </summary> /// <typeparam name="TRequest"></typeparam> /// <typeparam name="TResponse"></typeparam> public class DomainContextTransactionBehavior<TRequest, TResponse> : TransactionBehavior<DomainContext, TRequest, TResponse> { public DomainContextTransactionBehavior(DomainContext dbContext, ICapPublisher capBus, ILogger<DomainContextTransactionBehavior<TRequest, TResponse>> logger) : base(dbContext, capBus, logger) { } }具体的仓储实现类:
/// <summary> /// Order 仓储实现类 /// </summary> public class OrderRepository : Repository<Order, long, DomainContext>, IOrderRepository { public OrderRepository(DomainContext context) : base(context) { } }然后我们就需要注册仓储服务和数据库服务:
// 注册 MySql 数据库上下文 services.AddMySqlDomainContext(Configuration.GetValue<string>("MySql")); // 注册 仓储服务 services.AddRepositories();显然这两个是扩展服务:
/// <summary> /// 注册MySql服务 /// </summary> /// <param name="services"></param> /// <param name="connectionString"></param> /// <returns></returns> public static IServiceCollection AddMySqlDomainContext(this IServiceCollection services, string connectionString) { return services.AddDomainContext(builder => { // package: Pomelo.EntityFrameworkCore.MySql builder.UseMySql(connectionString); }); } /// <summary> /// 注册仓储服务 /// </summary> /// <param name="services"></param> /// <returns></returns> public static IServiceCollection AddRepositories(this IServiceCollection services) { services.AddScoped<IOrderRepository, OrderRepository>(); return services; }当我们启动的时候,如果数据库里面没有这个数据库,那么就会生成。
结下一节,简单介绍一下Mediator,这个是领域设计的驱动。
分类: .net core(web)重新整理 .net core 实践篇—————仓储层的具体实现[二十七]
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)