zoukankan      html  css  js  c++  java
  • 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 的简单实现,在 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()
                );
            }
        }
    }
    
  • 相关阅读:
    Title
    Title
    JS淘宝小广告
    JS淘宝浏览商品
    JS隐藏显示图片
    JS图片轮播
    C#连接数据库的方法
    让$(window).scroll()监听事件只执行一次
    axios发delete请求,后台收不到参数;
    .gitignore规则简介
  • 原文地址:https://www.cnblogs.com/zzqvq/p/10356193.html
Copyright © 2011-2022 走看看