[Abp 源码分析]七、仓储与 Entity Framework Core (2)

这里 AttachIfNot 作用是将实体附加到追踪上下文当中,如果你之前是通过 Get() 方法获取实体之后更改了某个实体,那么在调用 Context.ChangeTracker.Entries() 方法的时候会获取到已经发生变动的身体对象集合。

1.3 仓储的注入

仓储的注入操作发生在 AbpEntityFrameworkCoreModule 模块执行 Initialize() 方法的时候,在 Initialize() 方法内部调用了 RegisterGenericRepositoriesAndMatchDbContexes() 方法,其定义如下:

private void RegisterGenericRepositoriesAndMatchDbContexes() { // 查找所有数据库上下文 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; } using (IScopedIocResolver scope = IocManager.CreateScope()) { // 遍历数据库上下文 foreach (var dbContextType in dbContextTypes) { Logger.Debug("Registering DbContext: " + dbContextType.AssemblyQualifiedName); // 为数据库上下文每个实体注册仓储 scope.Resolve<IEfGenericRepositoryRegistrar>().RegisterForDbContext(dbContextType, IocManager, EfCoreAutoRepositoryTypes.Default); // 为自定义的 DbContext 注册仓储 IocManager.IocContainer.Register( Component.For<ISecondaryOrmRegistrar>() .Named(Guid.NewGuid().ToString("N")) .Instance(new EfCoreBasedSecondaryOrmRegistrar(dbContextType, scope.Resolve<IDbContextEntityFinder>())) .LifestyleTransient() ); } scope.Resolve<IDbContextTypeMatcher>().Populate(dbContextTypes); } }

方法很简单,注释已经说的很清楚了,就是遍历实体,通过 EfGenericRepositoryRegistrar 与 EfCoreBasedSecondaryOrmRegistrar 来注册仓储。

来看一下具体的注册操作:

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); if (primaryKeyType == typeof(int)) { // 建立仓储的封闭类型 var genericRepositoryType = repositoryInterface.MakeGenericType(entityTypeInfo.EntityType); 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 之外的类型 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() ); } } }

这里 RegisterForDbContext() 方法传入的这些开放类型其实是通过 EfCoreAutoRepositoryTypes.Default 属性指定,其定义:

public static class EfCoreAutoRepositoryTypes { public static AutoRepositoryTypesAttribute Default { get; } static EfCoreAutoRepositoryTypes() { Default = new AutoRepositoryTypesAttribute( typeof(IRepository<>), typeof(IRepository<,>), typeof(EfCoreRepositoryBase<,>), typeof(EfCoreRepositoryBase<,,>) ); } } 2.Entity Framework Core 2.1 工作单元

在之前的文章里面说过,Abp 本身只实现了一个抽象工作单元基类 UnitOfWorkBase ,而具体的事务处理是存放在具体的持久化模块里面进行实现的,在 EF Core 这里则是通过 EfCoreUnitOfWork 实现的。

首先看一下 EfCoreUnitOfWork 注入了哪些东西:

public class EfCoreUnitOfWork : UnitOfWorkBase, ITransientDependency { protected IDictionary<string, DbContext> ActiveDbContexts { get; } protected IIocResolver IocResolver { get; } private readonly IDbContextResolver _dbContextResolver; private readonly IDbContextTypeMatcher _dbContextTypeMatcher; private readonly IEfCoreTransactionStrategy _transactionStrategy; /// <summary> /// Creates a new <see cref="EfCoreUnitOfWork"/>. /// </summary> public EfCoreUnitOfWork( IIocResolver iocResolver, IConnectionStringResolver connectionStringResolver, IUnitOfWorkFilterExecuter filterExecuter, IDbContextResolver dbContextResolver, IUnitOfWorkDefaultOptions defaultOptions, IDbContextTypeMatcher dbContextTypeMatcher, IEfCoreTransactionStrategy transactionStrategy) : base( connectionStringResolver, defaultOptions, filterExecuter) { IocResolver = iocResolver; _dbContextResolver = dbContextResolver; _dbContextTypeMatcher = dbContextTypeMatcher; _transactionStrategy = transactionStrategy; ActiveDbContexts = new Dictionary<string, DbContext>(); } }

emmm,他注入的基本上都是与 EfCore 有关的东西。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wppjgx.html