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实例,是DbContextFactory工厂方法提供,它封装了将DbContextOptionsBuilder,以及连接字符串,
所需要的全部参数封装在AbpDbContextConfigurationContext里面

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


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

》单独创建DbContext的生命周期是TransientDependency,其依赖是DbContextOptions是工厂DbContextOptionFactory工厂模式进行创建的。
》如果使用仓储如IRespository创建,而默认使用EfCoreRepository<>创建,构造函数使用IDbContextProvider进行创建,
由于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 --->GetEnumerator
>IEumerable ------>GetEumerator
IQueryable ------> Type, Expression,IQueryProvider
  protected override IQueryable GetQueryable()
        {
            return DbSet.AsQueryable();
        }
 
 

IBasicRepository:在IReadOnlyBasicRespostory基础上,添加增加、删除、修改方法
IRepostory:在IReadOnlyRepostory和IBasicRepository基础上,再增加了删除表达树方法
而EfCoreRepository则包含了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(Action>)配置
options.Entity(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 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(option=>option.UseSqlServer()),
AbpDbContextOptions定义的方法Configure以及Configure
是对AbpDbContextConfigurationContext.DbContextOptions(DbContextOptionsBuilder).UseSqlServer(字符串)进行设置,相应字符串,在工厂创建
AbpDbContextConfigurationContext,引入IConnectionStringResolver,解析字符串
 
 

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

将DbContextOptions的工厂方法 注入容器里面,用于创建DbContext
而这个DbContext,在仓储方法是由UnitOfWorkDbContextProvider提供,
public static IServiceCollection AddAbpDbContext(
            this IServiceCollection services, 
            Action optionsBuilder = null)
            where TDbContext : AbpDbContext
        {
            services.AddMemoryCache();

            var options = new AbpDbContextRegistrationOptions(typeof(TDbContext), services);
            optionsBuilder?.Invoke(options);

            services.TryAddTransient(DbContextOptionsFactory.Create);

            foreach (var dbContextType in options.ReplacedDbContextTypes)
            {
                services.Replace(ServiceDescriptor.Transient(dbContextType, typeof(TDbContext)));
            }

            new EfCoreRepositoryRegistrar(options).AddRepositories();

            return services;
        }


配置
protected virtual void ConfigureExtraProperties(ModelBuilder modelBuilder, IMutableEntityType mutableEntityType)
            where TEntity : class
        {
            if (!typeof(IHasExtraProperties).IsAssignableFrom(typeof(TEntity)))
            {
                return;
            }

            modelBuilder.Entity(b =>
            {
                b.Property(x => ((IHasExtraProperties) x).ExtraProperties)
                    .HasConversion(
                        d => JsonConvert.SerializeObject(d, Formatting.None),
                        s => JsonConvert.DeserializeObjectstring, object>>(s)
                    )
                    .HasColumnName(nameof(IHasExtraProperties.ExtraProperties));
            });
        }

防并发的配置,IsConcurrencyToken

 protected virtual void ConfigureConcurrencyStampProperty(ModelBuilder modelBuilder, IMutableEntityType mutableEntityType)
            where TEntity : class
        {
            if (!typeof(IHasConcurrencyStamp).IsAssignableFrom(typeof(TEntity)))
            {
                return;
            }

            modelBuilder.Entity(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委托 的配置,  ListAbpDbContextConfigurationContext >>,我们使用主要到这个AbpDbContextOptions对里面AbpDbContextConfigurationContext委托配置

 

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

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

创建new AbpDbContextConfigurationContext()

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

返回到AbpDbContextConfigurationContext.DbContextOptions.Options,即是 DbContextOptions

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

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

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

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

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

 

 

 

 

AbpModelBuilderConfigurationOptions:

 

 

AbpDbContextConfigurationContext :DbContextOptionsBuilder

扩展方法:UseUseMySQL

 

DbContextCreationContext

 

 

 

 

AbpDbContextRegistrationOptions:

AbpEntityOptions:

AbpDbContextOptions:

AbpModelBuilderConfigurationOptions:

 

 

AbpDbContextConfigurationContext

DbContextCreationContext

 

 

 

 

 

 

AbpDbContextRegistrationOptions:

AbpEntityOptions:

AbpDbContextOptions:

AbpModelBuilderConfigurationOptions:

 

 

AbpDbContextConfigurationContext

DbContextCreationContext

 

 

 

 

 

 

你可能感兴趣的:(Ef Core)