ABP领域层定义仓储并实现
原文作者:圣杰
在原文作者上进行改正,适配ABP新版本。内容相同
一、先来介绍下仓储
仓储(Repository): 仓储用来操作数据库进行数据存取。仓储接口在领域层定义,而仓储的实现类应该写在基础设施层。
在ABP中,仓储类要实现IRepository
接口,接口定义了常用的增删改查以及聚合方法,其中包括同步及异步方法。主要包括以下方法:
ABP针对不同的ORM框架对该接口给予了默认的实现;
- 针对EntityFramework,提供了
EfRepositoryBase<TDbContext, TEntity, TPrimaryKey>
的泛型版本的实现方式。 - 针对NHibernate,提供了
NhRepositoryBase<TEntity, TPrimaryKey>
的泛型版本的实现方式。
泛型版本的实现就意味着,大多数的时候,这些方法已足已应付一般实体的需要。如果这些方法对于实体来说已足够,我们便不需要再去创建这个实体所需的仓储接口/类。
直接通过在应用服务层定义仓储引用,然后通过构造函数注入即可。在我们的应用服务层即可按以下方式使用Task仓储:
1.在xxxx.Application创建Tasks文件夹,并在其目录下创建Dtos及Services子文件夹。
2.在Services子文件夹下创建ITaskAppService接口及TaskAppService实现类
1 using Abp.Application.Services; 2 using System; 3 using System.Collections.Generic; 4 using System.Text; 5 6 namespace Coreqi.Tasks.Services 7 { 8 public interface ITaskAppServic:IApplicationService 9 { 10 11 } 12 }
1 using Abp.Domain.Repositories; 2 using System; 3 using System.Collections.Generic; 4 using System.Text; 5 6 namespace Coreqi.Tasks.Services 7 { 8 public class TaskAppService:ITaskAppServic 9 { 10 private readonly IRepository<Task> _taskRepository; 11 public TaskAppService(IRepository<Task> taskRepository) 12 { 13 _taskRepository = taskRepository; 14 } 15 } 16 }
二、如何实现自定义仓储
假设我们需要查找某个用户都分配哪些任务。
1.在领域层(xxxx.Core),创建IRepositories文件夹,然后定义IBackendTaskRepository。
1 using Abp.Domain.Repositories; 2 using Coreqi.Tasks; 3 using System; 4 using System.Collections.Generic; 5 using System.Text; 6 7 namespace Coreqi.IRepositories 8 { 9 /// <summary> 10 /// 自定义仓储示例 11 /// </summary> 12 public interface IBackendTaskRepository:IRepository<Task> 13 { 14 /// <summary> 15 /// 获取某个用户分配了哪些任务 16 /// </summary> 17 /// <param name="personId">用户Id</param> 18 /// <returns>任务列表</returns> 19 List<Task> GetTaskByAssignedPersonId(long personId); 20 } 21 }
2.在基础架构层(xxxx.EntityFrameworkCore=》EntityFrameworkCore=》Repositories),实现该仓储。
1 using Abp.EntityFrameworkCore; 2 using Coreqi.IRepositories; 3 using Coreqi.Tasks; 4 using System; 5 using System.Collections.Generic; 6 using System.Linq; 7 using System.Text; 8 9 namespace Coreqi.EntityFrameworkCore.Repositories 10 { 11 public class BackendTaskRepository : CoreqiRepositoryBase<Task>, IBackendTaskRepository 12 { 13 public BackendTaskRepository(IDbContextProvider<CoreqiDbContext> dbContextProvider) : base(dbContextProvider) 14 { 15 } 16 17 /// <summary> 18 /// 获取某个用户分配了哪些任务 19 /// </summary> 20 /// <param name="personId">用户Id</param> 21 /// <returns>任务列表</returns> 22 public List<Task> GetTaskByAssignedPersonId(long personId) 23 { 24 var query = GetAll(); 25 26 if (personId > 0) 27 { 28 query = query.Where(t => t.AssignedPersonId == personId); 29 } 30 31 return query.ToList(); 32 } 33 } 34 }
该仓储实现,继承自模板生成的
LearningMpaAbpRepositoryBase
泛型抽象类,然后再实现IBackendTaskRepository
接口。这里要显示声明实现类的有参构造函数,使用泛型的IDbContextProvider将数据库上下文的子类ChargeStationContext传给父类的构造函数。三、仓储的注意事项
- 仓储方法中,ABP自动进行数据库连接的开启和关闭。
- 仓储方法被调用时,数据库连接自动开启且启动事务。
- 当仓储方法调用另外一个仓储的方法,它们实际上共享的是同一个数据库连接和事务。
- 仓储对象都是暂时性的,因为IRepository接口默认继承自ITransientDependency接口。所以,仓储对象只有在需要注入的时候,才会由Ioc容器自动创建新实例。
- 默认的泛型仓储能满足我们大部分的需求。只有在不满足的情况下,才创建定制化的仓储。