重新整理 .net core 实践篇—————仓储层的具体实现[二十七]

重新整理 .net core 实践篇—————仓储层的具体实现[二十七],第1张

前言

简单整理一下仓储层。

正文

在共享层的基础建设类库中:

/// <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 实践篇—————仓储层的具体实现[二十七]

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/1006703.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-22
下一篇 2022-05-22

发表评论

登录后才能评论

评论列表(0条)

保存