概述
基础设施层是整个系统的⽀持层,通过对第三⽅类库的调⽤或系统的抽象和集成来实现对其他层的⽀持。
与传统架构不同在DDD中,数据库访问的具体实现(仓储)也被放在了基础设施层。
在DDD的理念中,基础设施层是为领域和用例的逻辑实现提供支撑。在前面的章节我也提到,在DDD的理念中,数据访问具体实现不是设计过程需要关注的重点,所以将具体访问数据库的代码放在了基础设施层。
概览
通常情况下,我们会将提供数据服务连接的相关类和方法存放于一个项目中,而将其他公共类,公共方法存放于另外的一个或多个项目中。这些自定义的公共类库,这里我就不具体讲述,请依据个人项目需要来进行规划设计。
基础设施层数据库连接服务主要包含以下组件:
仓储(Repository)实现:对领域层定义的仓储接口的实现类,用户封装对领域对象的数据持久化操作的具体实现。
在ABP框架下,基础设施层提供数据库访问的类库包含应用程序的数据库上下文(DbContext)、数据库映射、仓储的实现等信息。依据项目需要,我们可以通过CLI中的 -d 参数来选择使用EF Core或者MongoDB,分别会包含以下两个类库:
EntityFrameworkCore:是EF Core的基本集成包,支持SQL Server、MySQL、SQLite、Oracle、PostgreSQL数据库。默认使用SQL Server数据库。
MongoDB:以MongoDB为数据库的基础设施层类库。
实现细节
1
默认仓储
ABP提供了用于实体增删改查的默认仓储接口和实现类,在大多数情况下,我们只需要直接注入使用默认仓储 IRepository<TEntity, TKey> 即可,其中TEntity为需要操作的实体,TKey为该实体主键的数据类型。
使用默认仓储时,需要在EntityFrameworkCore项目的Module类中的 ConfigureServices 方法中加入以下代码用于给所有实体创建默认仓储:
context.Services.AddAbpDbContext<MyDbContext>(options =>{options.AddDefaultRepositories(includeAllEntities: true);});
其中MyDbContext为当前项目的数据上下文,includeAllEntities参数为true时会给所有实体、聚合根创建默认仓储,如果为false则只给聚合根创建默认仓储。
在默认仓储中,ABP提供了以下方法可供直接操作数据库:
GetAsync:通过lambda 表达式查询单个实体,如果存在多个满足条件的实体,则抛出 InvalidOperationException 异常。
FindAsync:通过lambda 表达式查询单个实体,如果存在多个满足条件的实体,则抛出 InvalidOperationException 异常。
InsertAsync:添加实体。
InsertManyAsync:批量添加。
UpdateAsync:更新实体。
UpdateManyAsync:批量修改。
DeleteAsync:删除实体,也可根据Lambda表达式删除。
DeleteManyAsync:批量删除。
GetListAsync:获取数据库中所有实体的列表。
GetPagedListAsync:分页获取实体集合。
GetCountAsync:获取数据库中所有实体的计数。
GetAsync方法和FindAsync方法的区别为:如果实体未找到,GetAsync抛出 EntityNotFoundException 异常,而FindAsync方法返回 null
另外,在很多情况下,我们希望获取 IQueryable 类型用于自定义Linq查询,在ABP 5.0版本之后,获取IQueryable方式改为 await _personRepository.GetQueryableAsync();
2
自定义仓储
如果默认仓储不能满足我们的需求,我们可以自定义仓储接口和实现。
自定义仓储接口声明存放与领域层,可继承自 IRepository<TEntity,TKey> ,其实现类存放与基础设施层,继承自 EfCoreRepository<TDbContext,TEntity,TKey> 或 MongoDbRepository<TDbContext, TEntity, TKey>
3
Dapper集成
在一些情况下,我们希望可以使用自定义的SQL语句进行更灵活的数据库操作或者执行存储过程调用等操作,而Dapper框架可以满足我们需求。
在ABP,Dapper框架并被没有完整的集成,而是依托于EF Core实现。也就意味着如果要使用Dapper,创建项目时,数据访问对象依旧选择EF Core。
当使用Dapper时,我们需要创建自定义仓储,并将其实现类继承自 DapperRepository<TDbContext> ,其中TDbContext为EF Core项目的数据上下文。
具体用法,我们可以参考官方提供的示例:
public class PersonDapperRepository : DapperRepository<MyAppDbContext>, ITransientDependency
{public PersonDapperRepository(IDbContextProvider<MyAppDbContext> dbContextProvider): base(dbContextProvider){}public virtual async Task<List<string>> GetAllPersonNames(){var dbConnection = await GetDbConnectionAsync();return (await dbConnection.QueryAsync<string>("select Name from People", transaction: await GetDbTransactionAsync())).ToList();}public virtual async Task<int> UpdatePersonNames(string name){var dbConnection = await GetDbConnectionAsync();return await dbConnection.ExecuteAsync("update People set Name = @NewName", new { NewName = name },await GetDbTransactionAsync());}
}
欢迎加入微信交流群
END
关注我获得
更多精彩