ABP仓储
简介
我们都知道ABP已经实现了仓储模式,支持EF core 和dapper 进行数据库的连接和管理,可以很方便的注入仓储来操作你的数据,不需要自己单独定义一个仓储来实现,通用的仓储实现了通用的crud接口和一些常用的方法
例如:
public class InvoiceAppService:IITransientDependency
{
private readonly IRepository<Invoice> _InvoiceRepository;
public InvoiceAppService(IRepository<Invoice> InvoiceRepository)
{
_InvoiceRepository=InvoiceRepository;
}
public void Invoice(xxx)
{
InvoiceRepository.Insert(xxx);
}
}
通用仓储的定义与实现
ABP仓储定义如下
- AbpRepositoryBase 仓储基类
- AutoRepositoryTypesAttribute 自动构建仓储,用于实体标记
- IRepository 仓储接口基本的定义
- IRepositoryOfTEntity 仓储接口定义,默认为int类型
- IRepositoryOfEntityAndTPrimaryKey 仓储接口定义,主键与实体类型由用户定义
- ISupportsExplicitLoading 显示加载
- RepositoryExtensions 仓储相关的扩展方法
通用仓储的定义
通用仓储是由IRepository定义的,仅仅是起到了一个标识的作用
public interface IRepository : ITransientDependency{}
真正定义了仓储定义的是在IRepositoryOfTEntityAndTPrimaryKey
中
public interface IRepository<TEntity, TPrimaryKey> : IRepository where TEntity : class, IEntity<TPrimaryKey>
{
// 增删改查方法定义.
}
可以看到它定义了两个泛型 TEntity 与 TPrimaryKey,表示了.实体与实体对应的主键标识
通用仓储的实现
在 Abp 库里面,有一个默认的抽象基类实现了仓储接口,这个基类内部主要注入了 IUnitOfWorkManager 用来控制事务,还有 IIocResolver 用来解析 Ioc 容器内部注册的组件
本身在这个抽象仓储类里面没有什么实质性的东西,它只是之前 IRepository
public class EfCoreRepositoryBase<TDbContext, TEntity, TPrimaryKey> :
AbpRepositoryBase<TEntity, TPrimaryKey>,
ISupportsExplicitLoading<TEntity, TPrimaryKey>,
IRepositoryWithDbContext
where TEntity : class, IEntity<TPrimaryKey>
where TDbContext : DbContext
{
// 获取ef上下文对象
public virtual TDbContext Context => _dbContextProvider.GetDbContext(MultiTenancySide);
// 实体表
public virtual DbSet<TEntity> Table => Context.Set<TEntity>();
// 数据库事务
public virtual DbTransaction Transaction
{
get
{
return (DbTransaction) TransactionProvider?.GetActiveTransaction(new ActiveTransactionProviderArgs
{
{"ContextType", typeof(TDbContext) },
{"MultiTenancySide", MultiTenancySide }
});
}
}
// 数据库连接
public virtual DbConnection Connection
{
get
{
var connection = Context.Database.GetDbConnection();
if (connection.State != ConnectionState.Open)
{
connection.Open();
}
return connection;
}
}
// 事务提供者,用于提供激活的事务
public IActiveTransactionProvider TransactionProvider { private get; set; }
// 上下文提供器
private readonly IDbContextProvider<TDbContext> _dbContextProvider;
// ctor
public EfCoreRepositoryBase(IDbContextProvider<TDbContext> dbContextProvider)
{
_dbContextProvider = dbContextProvider;
}
// 其余crud方法
}
通用仓储的注入
仓储的注入操作发生在 AbpEntityFrameworkCoreModule 模块执行 Initialize() 方法的时候,在 Initialize() 方法内部调用了 RegisterGenericRepositoriesAndMatchDbContexes() 方法,其定义如下:
public override void Initialize()
{
IocManager.RegisterAssemblyByConvention(typeof(AbpEntityFrameworkCoreModule).GetAssembly());
IocManager.IocContainer.Register(
Component.For(typeof(IDbContextProvider<>))
.ImplementedBy(typeof(UnitOfWorkDbContextProvider<>))
.LifestyleTransient()
);
RegisterGenericRepositoriesAndMatchDbContexes();
}
private void RegisterGenericRepositoriesAndMatchDbContexes()
{
// 获取所有ef上下文类型
var dbContextTypes =
_typeFinder.Find(type =>
{
var typeInfo = type.GetTypeInfo();
return typeInfo.IsPublic &&
!typeInfo.IsAbstract &&
typeInfo.IsClass &&
typeof(AbpDbContext).IsAssignableFrom(type);
});
if (dbContextTypes.IsNullOrEmpty())
{
Logger.Warn("No class found derived from AbpDbContext.");
return;
}
// 创建ioc容器作用域
using (IScopedIocResolver scope = IocManager.CreateScope())
{
// 遍历上下文
foreach (var dbContextType in dbContextTypes)
{
Logger.Debug("Registering DbContext: " + dbContextType.AssemblyQualifiedName);
// 为上下文每个实体注册仓储
scope.Resolve<IEfGenericRepositoryRegistrar>().RegisterForDbContext(dbContextType, IocManager, EfCoreAutoRepositoryTypes.Default);
// 为自定义的 上下文注册仓储
IocManager.IocContainer.Register(
Component.For<ISecondaryOrmRegistrar>()
.Named(Guid.NewGuid().ToString("N"))
.Instance(new EfCoreBasedSecondaryOrmRegistrar(dbContextType, scope.Resolve<IDbContextEntityFinder>()))
.LifestyleTransient()
);
}
//
scope.Resolve<IDbContextTypeMatcher>().Populate(dbContextTypes);
}
}
下面看看是怎么注册的吧
public void RegisterForDbContext(
Type dbContextType,
IIocManager iocManager,
AutoRepositoryTypesAttribute defaultAutoRepositoryTypesAttribute)
{
var autoRepositoryAttr = dbContextType.GetTypeInfo().GetSingleAttributeOrNull<AutoRepositoryTypesAttribute>() ?? defaultAutoRepositoryTypesAttribute;
RegisterForDbContext(
dbContextType,
iocManager,
autoRepositoryAttr.RepositoryInterface,
autoRepositoryAttr.RepositoryInterfaceWithPrimaryKey,
autoRepositoryAttr.RepositoryImplementation,
autoRepositoryAttr.RepositoryImplementationWithPrimaryKey
);
if (autoRepositoryAttr.WithDefaultRepositoryInterfaces)
{
RegisterForDbContext(
dbContextType,
iocManager,
defaultAutoRepositoryTypesAttribute.RepositoryInterface,
defaultAutoRepositoryTypesAttribute.RepositoryInterfaceWithPrimaryKey,
autoRepositoryAttr.RepositoryImplementation,
autoRepositoryAttr.RepositoryImplementationWithPrimaryKey
);
}
}
private void RegisterForDbContext(
Type dbContextType,
IIocManager iocManager,
Type repositoryInterface,
Type repositoryInterfaceWithPrimaryKey,
Type repositoryImplementation,
Type repositoryImplementationWithPrimaryKey)
{
// 遍历所有上下文类型
foreach (var entityTypeInfo in _dbContextEntityFinder.GetEntityTypeInfos(dbContextType))
{
// 获取主键的类型
var primaryKeyType = EntityHelper.GetPrimaryKeyType(entityTypeInfo.EntityType);
// 主键是int类型
if (primaryKeyType == typeof(int))
{
// 根据实体类型动态构建一个泛型类型 例如 IRepository<Book>
var genericRepositoryType = repositoryInterface.MakeGenericType(entityTypeInfo.EntityType;
// 确定IOC容器中没有注册过
if (!iocManager.IsRegistered(genericRepositoryType))
{
// 构建仓储实现类型
var implType = repositoryImplementation.GetGenericArguments().Length == 1
? repositoryImplementation.MakeGenericType(entityTypeInfo.EntityType)
: repositoryImplementation.MakeGenericType(entityTypeInfo.DeclaringType,
entityTypeInfo.EntityType);
// 注册
iocManager.IocContainer.Register(
Component
.For(genericRepositoryType)
.ImplementedBy(implType)
.Named(Guid.NewGuid().ToString("N"))
.LifestyleTransient()
);
}
}
// 如果主键不是int类型 构建如下类型:IRepostory<entity,key>
var genericRepositoryTypeWithPrimaryKey = repositoryInterfaceWithPrimaryKey.MakeGenericType(entityTypeInfo.EntityType,primaryKeyType);
if (!iocManager.IsRegistered(genericRepositoryTypeWithPrimaryKey))
{ // 构建仓储实现类
var implType = repositoryImplementationWithPrimaryKey.GetGenericArguments().Length == 2
? repositoryImplementationWithPrimaryKey.MakeGenericType(entityTypeInfo.EntityType, primaryKeyType)
: repositoryImplementationWithPrimaryKey.MakeGenericType(entityTypeInfo.DeclaringType, entityTypeInfo.EntityType, primaryKeyType);
// 注册
iocManager.IocContainer.Register(
Component
.For(genericRepositoryTypeWithPrimaryKey)
.ImplementedBy(implType)
.Named(Guid.NewGuid().ToString("N"))
.LifestyleTransient()
);
}
}
}