zoukankan      html  css  js  c++  java
  • Ef Core

    有两种方式对数据库进行配置:

     1、重写 DbContext.OnConfiguring(DbContextOptionsBuilder) 方法

    class MyDBContext : DBContext
    {
        ...
        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            optionsBuilder.UseSqlServer(@"connectionString");
        }
    }
    2、通过 DbContextOptionsBuilder 类创建 DbContextOptions实例,并通过构造函数 DbContext(DbContextOptions) 传递给 DbContext
    DbContext 必须具有的实例DbContextOptions才能执行任何工作
    • 数据库提供程序,若要使用,通常选择通过调用的方法,如UseSqlServerUseSqlite。 这些扩展方法需要相应的提供程序包,如Microsoft.EntityFrameworkCore.SqlServerMicrosoft.EntityFrameworkCore.Sqlite。 中定义的方法Microsoft.EntityFrameworkCore命名空间。
    • 任何必要的连接字符串或标识符的数据库实例中,通常作为参数传递到上述提供程序选择方法
    • 任何提供程序级别的可选行为选择器,通常还链接到提供程序选择方法调用中
    • 任何常规 EF Core 行为选择器,通常链接之后或之前提供程序选择器方法

    下面的示例将配置DbContextOptions若要使用 SQL Server 提供程序,在连接包含connectionString变量、 提供程序级别的命令超时,以及可使在中执行的所有查询 EF Core 行为选择器DbContext否跟踪默认情况下:

    optionsBuilder
        .UseSqlServer(connectionString, providerOptions=>providerOptions.CommandTimeout(60))
        .UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking);

    options = new DbContextOptionsBuilder<CholessContext>()
                   .UseInMemoryDatabase("choless")
                   .Options;
    using (var context = new MyDBContext(options))
    {
        ...
    }

    Abp提供的实例DbContextOption实例,是DbContextOptionsFactory工厂方法提供,它封装了将DbContextOptionsBuilder,以及连接字符串,
    所需要的全部参数封装在AbpDbContextConfigurationContext里面

    在AbpDbContextConfigurationContext扩展方法就可以直接使用UseSqlServer方法(字符串)


    而AbpDbContextOptions是再一层封装,目的是让应用上使用更加方便,即操作
    AbpDbContextConfigurationContext的委托方法。
    使用的是Config,PreConfigure以及Config<DbContext>、PreConfigure<DbContext>方法
    而它的使用,在DbContextOptionFactory方法,创建AbpDbContextConfigurationContext实例,再执行委托方法。

    》单独创建DbContext的生命周期是TransientDependency,其依赖是DbContextOptions是工厂DbContextOptionFactory工厂模式进行创建的。
    》如果使用仓储如IRespository创建,而默认使用EfCoreRepository<>创建,构造函数使用IDbContextProvider<TDbContext>进行创建,
    由于EfCoreRepository是实现IUnitOfWorkEnabled的接口,其下的所有方法都使用拦截器,创建一个工作单元
    进行注入IDbContextProvider是UnitOfWorkDbContextProvider,它需要在一个工作单元里,使用是IServiceScope,它是伴随着unitofwork的Dispose
    销毁而销毁,进行注入创建DbContext.
    它的在UnitOfWork的key值是"DbContext的FullName_连接字符串"
    UnitOfWork.Option.IsTransational若是则使用key="EntityFrameWork_字符串",则使用创建一个事务
    dbContext.database.BeginTransation()

    而AbpDbContextRegisterOptions,则对仓储的实现类进行配置,默认值、使用哪一个仓储实现类,替换DbContext进行配置
    默认的IReadOnlyBasicRepostory(只有读方法),
    IReadOnlyRepostory(添加WithDetails(表达树)方法)IQueryable方法
    》IEumerable<T> --->GetEnumerator
    >IEumerable ------>GetEumerator
    IQueryable ------> Type, Expression,IQueryProvider
      protected override IQueryable<TEntity> GetQueryable()
            {
                return DbSet.AsQueryable();
            }
    
    

    IBasicRepository:在IReadOnlyBasicRespostory基础上,添加增加、删除、修改方法
    IRepostory:在IReadOnlyRepostory和IBasicRepository基础上,再增加了删除表达树方法
    而EfCoreRepository<TDbContext,TEntity,Tkey>则包含了IRepository的全部实现方法

    每一个数据库实现都继承实现RepositoryRegisterBase<AbpDbContextRegistrationOptions>,基类实现是AddDefaultRepositories()是增加
    自定义的仓储和登记默认仓储(官方实现还是自定义)。

    扩充是GetEntityTypes,GetRepositoryType方法
      protected override Type GetRepositoryType(Type dbContextType, Type entityType)
            {
                return typeof(EfCoreRepository<,>).MakeGenericType(dbContextType, entityType);
            }
    
            protected override Type GetRepositoryType(Type dbContextType, Type entityType, Type primaryKeyType)
            {
                return typeof(EfCoreRepository<,,>).MakeGenericType(dbContextType, entityType, primaryKeyType);
            }
    
    
    在EfCoreRepositoryRegistrar是关系数据库的实现方法

    WithDetails()默认是Option.DefaultWithDetails(GetQueryable()),而
    在AbpDbContextRegisterOptions下Entity<T>(Action<AbpEntityOptions<>>)配置
    options.Entity<Person>(opt =>
                    {
                        opt.DefaultWithDetailsFunc = q => q.Include(p => p.Phones);
                    });
    
    
    

    而在XXX.EntityFrameWorkCore,则应用SeviceConfigurationContext.services.AddAbpDbContext(option=>{???})
    对每一个实体的仓储进行设置,对于默认仓储,默认仓储是优先使用Option配置的,若没有配置,则使用EfCoreRepository<>

    protected virtual bool ShouldRegisterDefaultRepositoryFor(Type entityType)     
    {
    //是否注册默认仓储,若false,则不注册
    if (!Options.RegisterDefaultRepositories) { return false; } //如果自定义仓储包含,则不注册默认仓储 if (Options.CustomRepositories.ContainsKey(entityType)) { return false; } //如果设置不包括所有实体,而且当前不是聚合根类型,则返回false,(聚合根是默认要仓储的) if (!Options.IncludeAllEntitiesForDefaultRepositories && !typeof(IAggregateRoot).IsAssignableFrom(entityType)) { return false; } return true; }
    
    

    1、Entity<>
    2、AddDefaultRepositories===》登记了默认的仓储
    3、AddRepository ========》自定义仓储 CustomRepositories[entitype]=repositoryType
    3、SetDefaultRepositoryClass ===》默认是使用EfcoreRepository,可以自定义设置,分两个,一个是有key,一个无key的,
    4、ReplaceDbContext => List<type> ReplaceDbContextTypes,就是将此DbContext替换成OriginDbContext(即AddAbpContext定义那个)

    AddAbpDbContext中使用到
       foreach (var dbContextType in options.ReplacedDbContextTypes)
                {
                    services.Replace(ServiceDescriptor.Transient(dbContextType, typeof(TDbContext)));
                }
    
    
    AbpContext:
    1、ModelBuilder,配置审计、租户等数据映射
    2、利用IEventChangeEventHelper进行事件发送
    3、利用IEventHistoryHelper对日记的记录
    4、数据筛选,主要是软删除、租户




    ABP使用,引用Volo.Abp.EntityFrameworkCore,以及具体的数据库如Volo.Abp.EntityFrameworkCore.SqlServer
    它的步骤在Configure(ServiceConfigurationContext context)方法
    执行Configure<AbpDbContextOptions>(option=>option.UseSqlServer()),
    AbpDbContextOptions定义的方法Configure以及Configure<TDbContext>,
    是对AbpDbContextConfigurationContext.DbContextOptions(DbContextOptionsBuilder).UseSqlServer(字符串)进行设置,相应字符串,在工厂创建
    AbpDbContextConfigurationContext,引入IConnectionStringResolver,解析字符串
    
    

    AbpDbContext上下文进行服务进行注册,包括默认仓储,特定仓储,以及DbContext替换,(委托方法)

    将DbContextOptions<TDbContext>的工厂方法 注入容器里面,用于创建DbContext
    而这个DbContext,在仓储方法是由UnitOfWorkDbContextProvider提供,
    public static IServiceCollection AddAbpDbContext<TDbContext>(
                this IServiceCollection services, 
                Action<IAbpDbContextRegistrationOptionsBuilder> optionsBuilder = null)
                where TDbContext : AbpDbContext<TDbContext>
            {
                services.AddMemoryCache();
    
                var options = new AbpDbContextRegistrationOptions(typeof(TDbContext), services);
                optionsBuilder?.Invoke(options);
    
                services.TryAddTransient(DbContextOptionsFactory.Create<TDbContext>);
    
                foreach (var dbContextType in options.ReplacedDbContextTypes)
                {
                    services.Replace(ServiceDescriptor.Transient(dbContextType, typeof(TDbContext)));
                }
    
                new EfCoreRepositoryRegistrar(options).AddRepositories();
    
                return services;
            }


    配置
    protected virtual void ConfigureExtraProperties<TEntity>(ModelBuilder modelBuilder, IMutableEntityType mutableEntityType)
                where TEntity : class
            {
                if (!typeof(IHasExtraProperties).IsAssignableFrom(typeof(TEntity)))
                {
                    return;
                }
    
                modelBuilder.Entity<TEntity>(b =>
                {
                    b.Property(x => ((IHasExtraProperties) x).ExtraProperties)
                        .HasConversion(
                            d => JsonConvert.SerializeObject(d, Formatting.None),
                            s => JsonConvert.DeserializeObject<Dictionary<string, object>>(s)
                        )
                        .HasColumnName(nameof(IHasExtraProperties.ExtraProperties));
                });
            }

    防并发的配置,IsConcurrencyToken

     protected virtual void ConfigureConcurrencyStampProperty<TEntity>(ModelBuilder modelBuilder, IMutableEntityType mutableEntityType)
                where TEntity : class
            {
                if (!typeof(IHasConcurrencyStamp).IsAssignableFrom(typeof(TEntity)))
                {
                    return;
                }
    
                modelBuilder.Entity<TEntity>(b =>
                {
                    b.Property(x => ((IHasConcurrencyStamp) x).ConcurrencyStamp)
                        .IsConcurrencyToken()
                        .HasColumnName(nameof(IHasConcurrencyStamp.ConcurrencyStamp));
                });
            }

    更新了需要赋值旧值,新值  -------》ef的特性

         protected virtual void UpdateConcurrencyStamp(EntityEntry entry)
            {
                var entity = entry.Entity as IHasConcurrencyStamp;
                if (entity == null)
                {
                    return;
                }
    
                Entry(entity).Property(x => x.ConcurrencyStamp).OriginalValue = entity.ConcurrencyStamp;
                entity.ConcurrencyStamp = Guid.NewGuid().ToString("N");
            }


    AbpDbContextRegistrationOptions:利用IServicsCollection对默认仓储,特定实体的配置,以及DbContext的替换,这个功能已经很强大

     

    AbpEntityOptions:

     

     DbContextCreationContext:只有connectionStringName、connectionString的包装,有 Use方法(对旧的DbContextCreationContext释放)

    AbpDbContextConfigurationContext:只有ConnectionString、ConnectionStringName、DbContextOptionsBuilder、DbConnection包装

    AbpDbContextOptions:  =>对AbpDbContextConfigurationContext委托 的配置,  List<Action<AbpDbContextConfigurationContext >>,我们使用主要到这个AbpDbContextOptions对里面AbpDbContextConfigurationContext委托配置

    它在DbContextOptionsFactory.Create方法,创建DbContextOptions<TDbContext>,而这个参数用于创建AbpDbContext实例

    它的操作步骤是它获取DbContextCreationContext,使用到ConnectionStringNameAttribute上的connectionStringName,使用IConnectionStringResolver解析到字符串)

    创建new AbpDbContextConfigurationContext<TDbContext>()

    执行PreConfigure、Configure的方法(每个都是Default通用方法,以及具体的AbpDbContextConfigurationContext<TDbContext>的方法)

    返回到AbpDbContextConfigurationContext.DbContextOptions.Options,即是 DbContextOptions<TDbContext>

    创建这个Option的工厂方法加入到IServiceCollection容器里面

    而自身创建XXXDbContext,它需要它需要继承自 AbpDbContext<T>,此类的是派生于ITransientDependency,在依赖注入系统会自动注入XXXDbContext,

    而仓储的调用注入是IDbContextProvider<TDbContext>,它的实现是UnitOfWorkDbContextProvider,是提供具体的XXXDbContext,

    要注意是一个工作单元里里面也存储一个实例字典实现方便使用,它的索引值是$DbContext全称_连接字符串,它是随着工作单元的释放也释放

     context.Services.TryAddTransient(typeof(IDbContextProvider<>), typeof(UnitOfWorkDbContextProvider<>));

     

     

    Add-Migration 添加一个新的迁移(名词),string是迁移的名称
    remove-Migration 删除上一次的迁移
    Update-Database 更新最近一次的迁移到数据库(有时候可能与原来的数据库产生冲突,所以可能并不能迁移到数据库)
    Update-Database -Migration 0 表示清空数据库,回到空数据库状态
    Script-Migration 查看迁移脚本

     

     

    AbpModelBuilderConfigurationOptions:

     

     

    AbpDbContextConfigurationContext :DbContextOptionsBuilder

    扩展方法:UseUseMySQL

     

    DbContextCreationContext

     

     

     

    AbpDbContextRegistrationOptions:

    AbpEntityOptions:

    AbpDbContextOptions:

    AbpModelBuilderConfigurationOptions:

     

     

    AbpDbContextConfigurationContext

    DbContextCreationContext

     

     

     

     

     

    AbpDbContextRegistrationOptions:

    AbpEntityOptions:

    AbpDbContextOptions:

    AbpModelBuilderConfigurationOptions:

    AbpDbContextConfigurationContext

    DbContextCreationContext

  • 相关阅读:
    Duilib 控件类html富文本绘制
    再谈如何使用Taglist?
    如何让vim自动显示函数声明-使用 echofunc.vim插件
    vim 标签页 tabnew 等的操作命令
    php数组操作集锦- 掌握了数组操作, 也就掌握了php
    php字符串操作集锦
    thinkphp疑难解决4
    如何保存gnome的linux的 会话?相当于windows下的休眠?
    开发thinkphp的第一步就是给Application目录(不包括其下的文件)777权限, 关闭selinux
    如何更改gnome-screenshot的默认的保存路径?
  • 原文地址:https://www.cnblogs.com/cloudsu/p/11942981.html
Copyright © 2011-2022 走看看