简介

我们都知道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 的简单实现,在 EfCoreRepositoryBase 类当中则才是具体调用 EF Core API 的实现

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()
);
}
}
}

最新文章

  1. Python Day20
  2. 《Linux内核分析》实验一
  3. 图片压缩工具optipng/jpegoptim安装
  4. docker-5 docker仓库
  5. 我的开发框架之ORM框架
  6. 《lucene原理与代码分析》笔记
  7. Java多线程学习总结--线程同步(2)
  8. POST 一张 图像的调试来认识 http post
  9. Burp Suite Walkthrough(中文版)
  10. ImageList半透明,Alpha通道bug处理。
  11. lc面试准备:Reverse Bits
  12. iOS播放短的音效
  13. Myeclipse 设定文件的默认打开方式
  14. Docker入门之--基础知识
  15. day4 liaoxuefeng--调试、线程、正则表达式
  16. pytorch的backward
  17. java实验四《Android程序设计》实验报告
  18. mysql防注入
  19. 新建maven工程使用webapp插件弹出javax.servlet.http.HttpServlet was not found on the Java Build Path异常
  20. HDU 1978 How many ways(经典记忆化搜索)

热门文章

  1. JNI_Z
  2. eclipse - unresolved inclusion: &lt;stdio.h&gt;
  3. java文件读写常用方法
  4. jsp:jstl标签之控制流程
  5. MySQL 分区知识点(三)
  6. mysql 自增长 AUTO_INCREMENT
  7. CSS3 之 RGBa 可透明颜色
  8. 31 python下实现并发编程
  9. hdu-2544-最短路(dijkstra算法模板)
  10. LeetCode Second Minimum Node In a Binary Tree