<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      【EF Core】DbContext是如何識別出實體集合的

      在開始之前說明一下,你不要指望閱讀完本文后會得到光,就算得到光你也未必能變成迪迦。本文老周僅介紹原理,可以給部分大伙伴們解惑。

      咱們都知道,在派生 DbContext 類時,集體類的集合用 DbSet<TEntity> 表示,而咱們最常用的方法是在 DbContext 的派生類中公開 DbSet<TEntity> 屬性。但在實例化 DbContext 后,我們并未給這些屬性賦值,就能查詢數據了,那么,DbContext 類(包括其子類)是如何識別出這些公共屬性并填充數據的?

      好,主題已經打開,接下來老周就開始表演了。有大伙伴會說了:切,這個看看源碼不就知道了。是的,但有些人天生懶啊,不想看,那老周幫你看。

      首先,咱們要了解,DbContext 類是如何維護實體集合的?DbContext 類中有這么個字段聲明:

       private Dictionary<(Type Type, string? Name), object>? _sets;

      這行代碼老周嚴重希望你能看懂,看不懂會很麻煩的喲。這是一個字典類型,沒錯吧。然后,Key是啥類型,Value是啥類型?

      Key:是一個二元元組,第一項為 Type 對象,第二項為字符串對象。type 指的是實體類的 Type,name 指的是你為這個實體集合分配的名字。有伙伴會問,我怎么給它命名,DbSet 實例又不是我創建的?不急,請看下文;

      Value:猜得出來,這是與實體集合相關的實例,DbSet<>,實際類型是內部類 InternalDbSet<TEntity>。這個后面咱們再說。

      咱們先不去關心 DbSet<TEntity> 實例是怎么創建的(因為這里面要繞繞彎子),至少咱們知道:在DbContext上聲明的實體集合是緩存到一個字典中的。而把集合實例添加到字典中的是一個名為 GetOrAddSet 的方法。注意該方法是顯示實現了 IDbSetCache 接口的??纯催@個接口的定義:

      public interface IDbSetCache
      {
          
          object GetOrAddSet(IDbSetSource source, [DynamicallyAccessedMembers(IEntityType.DynamicallyAccessedMemberTypes)] Type type);
      
          
          object GetOrAddSet(
              IDbSetSource source,
              string entityTypeName,
              [DynamicallyAccessedMembers(IEntityType.DynamicallyAccessedMemberTypes)] Type type);
      
          
          IEnumerable<object> GetSets();
      }

      IDbSetSource 接口的實現者就是跟創建 DbSet 實例有關的,咱們先忽略它。把注意放那兩個重載方法 GetOrAddSet 上,它的功能就是獲取或者添加實體集合的引用。咱們看到,這兩個重載的區別在:1、以Type為標識添加;2、以Type + name為標識添加。而 DbContext 類是顯式實現了 IDbSetCache 接口的,即咱們上面提到過的,就是把 DbSet 實例存到那個名為 _sets 的字典中。

          object IDbSetCache.GetOrAddSet(
              IDbSetSource source,
              [DynamicallyAccessedMembers(IEntityType.DynamicallyAccessedMemberTypes)] Type type)
          {
              CheckDisposed();
      
              _sets ??= [];
      
              if (!_sets.TryGetValue((type, null), out var set))
              {
                  set = source.Create(this, type);
                  _sets[(type, null)] = set;
                  _cachedResettableServices = null;
              }
      
              return set;
          }
      
      
          object IDbSetCache.GetOrAddSet(
              IDbSetSource source,
              string entityTypeName,
              [DynamicallyAccessedMembers(IEntityType.DynamicallyAccessedMemberTypes)] Type type)
          {
              CheckDisposed();
      
              _sets ??= [];
      
              if (!_sets.TryGetValue((type, entityTypeName), out var set))
              {
                  set = source.Create(this, entityTypeName, type);
                  _sets[(type, entityTypeName)] = set;
                  _cachedResettableServices = null;
              }
      
              return set;
          }

      當添加的實體集合有名字時,字典的Key是由 type 和 entiyTypeName 組成;當集合不提供名字時,Key 就由 type 和 null 組成。

      然后,DbContext 類公開一組重載方法,封裝了 GetOrAddSet 方法的調用。

          public virtual DbSet<TEntity> Set<[DynamicallyAccessedMembers(IEntityType.DynamicallyAccessedMemberTypes)] TEntity>()
              where TEntity : class
              => (DbSet<TEntity>)((IDbSetCache)this).GetOrAddSet(DbContextDependencies.SetSource, typeof(TEntity));
      
      
          public virtual DbSet<TEntity> Set<[DynamicallyAccessedMembers(IEntityType.DynamicallyAccessedMemberTypes)] TEntity>(string name)
              where TEntity : class
              => (DbSet<TEntity>)((IDbSetCache)this).GetOrAddSet(DbContextDependencies.SetSource, name, typeof(TEntity));

       

      根據這個邏輯,那么,咱們在繼承 DbContext 類時,這樣寫也可以(假設實體類為 Student):

      public class MyDbContext : DbContext
      {
            public DbSet<Student> Students => Set<Student>();
            // 或者
            public DbSet<Student> Students => Set<Student>("stu");
      }

      不過,咱們通常的寫法是實體集合作為公共屬性:

      public class MyDbContext : DbContext
      {
            public DbSet<Student> Students { get; set; }
      }

      那 DbContext 類是怎么識別并調用 GetOrAddSet 方法的?

      這就要用到另一個輔助—— IDbSetInitializer,其實現類為 DbSetInitializer。

      public class DbSetInitializer : IDbSetInitializer
      {
          private readonly IDbSetFinder _setFinder;
          private readonly IDbSetSource _setSource;
      
          
          public DbSetInitializer(
              IDbSetFinder setFinder,
              IDbSetSource setSource)
          {
              _setFinder = setFinder;
              _setSource = setSource;
          }
      
          
          public virtual void InitializeSets(DbContext context)
          {
              foreach (var setInfo in _setFinder.FindSets(context.GetType()).Where(p => p.Setter != null))
              {
                  setInfo.Setter!.SetClrValueUsingContainingEntity(
                      context,
                      ((IDbSetCache)context).GetOrAddSet(_setSource, setInfo.Type));
              }
          }
      }

      這個 InitializeSets 方法就是在 DbContext 類的構造函數中調用的。

          public DbContext(DbContextOptions options)
          {
              ……
             
              ServiceProviderCache.Instance.GetOrAdd(options, providerRequired: false)
                  .GetRequiredService<IDbSetInitializer>()
                  .InitializeSets(this);
      
              EntityFrameworkMetricsData.ReportDbContextInitializing();
          }

      由于各種輔助類型間有依賴關系,因此,EF Core 內部其實也使用了服務容器技術來自動實例化。咱們回到上面 InitializeSets 方法的實現代碼上。從源代碼中我們看到,其實完成從 DbContext 的公共屬性識別 DbSet<> 這一功能的是名為 IDbSetFinder 的組件,它的內部實現類為 DbSetFinder。

      public class DbSetFinder : IDbSetFinder
      {
          private readonly ConcurrentDictionary<Type, IReadOnlyList<DbSetProperty>> _cache = new();
      
          public virtual IReadOnlyList<DbSetProperty> FindSets(Type contextType)
              => _cache.GetOrAdd(contextType, FindSetsNonCached);
      
          private static DbSetProperty[] FindSetsNonCached(Type contextType)
          {
              var factory = ClrPropertySetterFactory.Instance;
      
              return contextType.GetRuntimeProperties()
                  .Where(
                      p => !&& !&& p.DeclaringType != typeof&&&& p.PropertyType.GetGenericTypeDefinition() == typeof(DbSet<>))
                  .OrderBy(p => p.Name)
                  .Select(
                      p => new DbSetProperty(
                          p.Name,
                          p.PropertyType.GenericTypeArguments.Single(),
                          p.SetMethod == null ? null : factory.Create(p)))
                  .ToArray();
          }
      }

      總結一下,就是在 DbContext 的派生類中查找符合以下條件的屬性:

      1、非靜態屬性;

      2、不能是索引器;

      3、屬性是 DbSet<> 類型,并且有泛型參數(即實體類型);

      4、外加一條,屬性具有 set 訪問器(這個條件是在 InitializeSets 方法的代碼中,Where 方法篩選出來)。

       

      到了這里,本文的主題就有了答案了:

      DbContext 構造函數 --> IDbSetInitializer --> IDbSetFinder

      還差一步,前面咱們說過,DbSet<> 實例是由 IDbSetSource 負責創建的,其內部實現類是 DbSetSource。

      public class DbSetSource : IDbSetSource
      {
          private static readonly MethodInfo GenericCreateSet
              = typeof(DbSetSource).GetTypeInfo().GetDeclaredMethod(nameof(CreateSetFactory))!;
      
          private readonly ConcurrentDictionary<(Type Type, string? Name), Func<DbContext, string?, object>> _cache = new();
      
          public virtual object Create(DbContext context, Type type)
              => CreateCore(context, type, null, GenericCreateSet);
      
      
          public virtual object Create(DbContext context, string name, Type type)
              => CreateCore(context, type, name, GenericCreateSet);
      
          private object CreateCore(DbContext context, Type type, string? name, MethodInfo createMethod)
              => _cache.GetOrAdd(
                  (type, name),
                  static (t, createMethod) => (Func<DbContext, string?, object>)createMethod
                      .MakeGenericMethod(t.Type)
                      .Invoke(null, null)!,
                  createMethod)(context, name);
      
          [UsedImplicitly]
          private static Func<DbContext, string?, object> CreateSetFactory<TEntity>()
              where TEntity : class
              => (c, name) => new InternalDbSet<TEntity>(c, name);
      }

      所以,默認創建的 DbSet<> 實例其實是 InternalDbSet<TEntity> 類型。

      所有的組件都是通過 EntityFrameworkServicesBuilder 類的相關方法來添加到服務容器中的。

          public virtual EntityFrameworkServicesBuilder TryAddCoreServices()
          {
              TryAdd<IDbSetFinder, DbSetFinder>();
              TryAdd<IDbSetInitializer, DbSetInitializer>();
              TryAdd<IDbSetSource, DbSetSource>();
              TryAdd<IEntityFinderSource, EntityFinderSource>();
              TryAdd<IEntityMaterializerSource, EntityMaterializerSource>();
              TryAdd<IProviderConventionSetBuilder, ProviderConventionSetBuilder>();
              TryAdd<IConventionSetBuilder, RuntimeConventionSetBuilder>();
              TryAdd<IModelCustomizer, ModelCustomizer>();
              TryAdd<IModelCacheKeyFactory, ModelCacheKeyFactory>();
              TryAdd<ILoggerFactory>(p => ScopedLoggerFactory.Create(p, null));
              TryAdd<IModelSource, ModelSource>();
              TryAdd<IModelRuntimeInitializer, ModelRuntimeInitializer>();
              TryAdd<IInternalEntityEntrySubscriber, InternalEntityEntrySubscriber>();
              TryAdd<IEntityEntryGraphIterator, EntityEntryGraphIterator>();
              TryAdd<IEntityGraphAttacher, EntityGraphAttacher>();
              TryAdd<IValueGeneratorCache, ValueGeneratorCache>();
              TryAdd<IKeyPropagator, KeyPropagator>();
              TryAdd<INavigationFixer, NavigationFixer>();
              TryAdd<ILocalViewListener, LocalViewListener>();
              TryAdd<IStateManager, StateManager>();
              TryAdd<IConcurrencyDetector, ConcurrencyDetector>();
              TryAdd<IInternalEntityEntryNotifier, InternalEntityEntryNotifier>();
              TryAdd<IValueGenerationManager, ValueGenerationManager>();
              TryAdd<IChangeTrackerFactory, ChangeTrackerFactory>();
              TryAdd<IChangeDetector, ChangeDetector>();
              TryAdd<IDbContextServices, DbContextServices>();
              TryAdd<IDbContextDependencies, DbContextDependencies>();
              TryAdd<IDatabaseFacadeDependencies, DatabaseFacadeDependencies>();
              TryAdd<IValueGeneratorSelector, ValueGeneratorSelector>();
              TryAdd<IModelValidator, ModelValidator>();
              TryAdd<IExecutionStrategyFactory, ExecutionStrategyFactory>();
              TryAdd(p => p.GetRequiredService<IExecutionStrategyFactory>().Create());
              TryAdd<ICompiledQueryCache, CompiledQueryCache>();
              TryAdd<IAsyncQueryProvider, EntityQueryProvider>();
              TryAdd<IQueryCompiler, QueryCompiler>();
              TryAdd<ICompiledQueryCacheKeyGenerator, CompiledQueryCacheKeyGenerator>();
              TryAdd<ISingletonOptionsInitializer, SingletonOptionsInitializer>();
              TryAdd(typeof(IDiagnosticsLogger<>), typeof(DiagnosticsLogger<>));
              TryAdd<IInterceptors, Interceptors>();
              TryAdd<IInterceptorAggregator, SaveChangesInterceptorAggregator>();
              TryAdd<IInterceptorAggregator, IdentityResolutionInterceptorAggregator>();
              TryAdd<IInterceptorAggregator, QueryExpressionInterceptorAggregator>();
              TryAdd<ILoggingOptions, LoggingOptions>();
              TryAdd<ICoreSingletonOptions, CoreSingletonOptions>();
              TryAdd<ISingletonOptions, ILoggingOptions>(p => p.GetRequiredService<ILoggingOptions>());
              TryAdd<ISingletonOptions, ICoreSingletonOptions>(p => p.GetRequiredService<ICoreSingletonOptions>());
              TryAdd(p => GetContextServices(p).Model);
              TryAdd<IDesignTimeModel>(p => new DesignTimeModel(GetContextServices(p)));
              TryAdd(p => GetContextServices(p).CurrentContext);
              TryAdd<IDbContextOptions>(p => GetContextServices(p).ContextOptions);
              TryAdd<IResettableService, ILazyLoaderFactory>(p => p.GetRequiredService<ILazyLoaderFactory>());
              TryAdd<IResettableService, IStateManager>(p => p.GetRequiredService<IStateManager>());
              TryAdd<IResettableService, IDbContextTransactionManager>(p => p.GetRequiredService<IDbContextTransactionManager>());
              TryAdd<IEvaluatableExpressionFilter, EvaluatableExpressionFilter>();
              TryAdd<IValueConverterSelector, ValueConverterSelector>();
              TryAdd<IConstructorBindingFactory, ConstructorBindingFactory>();
              TryAdd<ILazyLoaderFactory, LazyLoaderFactory>();
              TryAdd<ILazyLoader>(p => p.GetRequiredService<ILazyLoaderFactory>().Create());
              TryAdd<IParameterBindingFactories, ParameterBindingFactories>();
              TryAdd<IMemberClassifier, MemberClassifier>();
              TryAdd<IPropertyParameterBindingFactory, PropertyParameterBindingFactory>();
              TryAdd<IParameterBindingFactory, LazyLoaderParameterBindingFactory>();
              TryAdd<IParameterBindingFactory, ContextParameterBindingFactory>();
              TryAdd<IParameterBindingFactory, EntityTypeParameterBindingFactory>();
              TryAdd<IMemoryCache>(_ => new MemoryCache(new MemoryCacheOptions { SizeLimit = 10240 }));
              TryAdd<IUpdateAdapterFactory, UpdateAdapterFactory>();
              TryAdd<IQueryCompilationContextFactory, QueryCompilationContextFactory>();
              TryAdd<IQueryTranslationPreprocessorFactory, QueryTranslationPreprocessorFactory>();
              TryAdd<IQueryTranslationPostprocessorFactory, QueryTranslationPostprocessorFactory>();
              TryAdd<INavigationExpansionExtensibilityHelper, NavigationExpansionExtensibilityHelper>();
              TryAdd<IExceptionDetector, ExceptionDetector>();
              TryAdd<IAdHocMapper, AdHocMapper>();
              TryAdd<IJsonValueReaderWriterSource, JsonValueReaderWriterSource>();
              TryAdd<ILiftableConstantFactory, LiftableConstantFactory>();
              TryAdd<ILiftableConstantProcessor, LiftableConstantProcessor>();
      
              TryAdd(
                  p => p.GetService<IDbContextOptions>()?.FindExtension<CoreOptionsExtension>()?.DbContextLogger
                      ?? new NullDbContextLogger());
      
              // This has to be lazy to avoid creating instances that are not disposed
              ServiceCollectionMap
                  .TryAddSingleton<DiagnosticSource>(_ => new DiagnosticListener(DbLoggerCategory.Name));
      
              ServiceCollectionMap.GetInfrastructure()
                  .AddDependencySingleton<LazyLoaderParameterBindingFactoryDependencies>()
                  .AddDependencySingleton<DatabaseProviderDependencies>()
                  .AddDependencySingleton<ModelSourceDependencies>()
                  .AddDependencySingleton<ValueGeneratorCacheDependencies>()
                  .AddDependencySingleton<ModelValidatorDependencies>()
                  .AddDependencySingleton<TypeMappingSourceDependencies>()
                  .AddDependencySingleton<ModelCustomizerDependencies>()
                  .AddDependencySingleton<ModelCacheKeyFactoryDependencies>()
                  .AddDependencySingleton<ValueConverterSelectorDependencies>()
                  .AddDependencySingleton<EntityMaterializerSourceDependencies>()
                  .AddDependencySingleton<EvaluatableExpressionFilterDependencies>()
                  .AddDependencySingleton<RuntimeModelDependencies>()
                  .AddDependencySingleton<ModelRuntimeInitializerDependencies>()
                  .AddDependencySingleton<NavigationExpansionExtensibilityHelperDependencies>()
                  .AddDependencySingleton<JsonValueReaderWriterSourceDependencies>()
                  .AddDependencySingleton<LiftableConstantExpressionDependencies>()
                  .AddDependencyScoped<ProviderConventionSetBuilderDependencies>()
                  .AddDependencyScoped<QueryCompilationContextDependencies>()
                  .AddDependencyScoped<StateManagerDependencies>()
                  .AddDependencyScoped<ExecutionStrategyDependencies>()
                  .AddDependencyScoped<CompiledQueryCacheKeyGeneratorDependencies>()
                  .AddDependencyScoped<QueryContextDependencies>()
                  .AddDependencyScoped<QueryableMethodTranslatingExpressionVisitorDependencies>()
                  .AddDependencyScoped<QueryTranslationPreprocessorDependencies>()
                  .AddDependencyScoped<QueryTranslationPostprocessorDependencies>()
                  .AddDependencyScoped<ShapedQueryCompilingExpressionVisitorDependencies>()
                  .AddDependencyScoped<ValueGeneratorSelectorDependencies>()
                  .AddDependencyScoped<DatabaseDependencies>()
                  .AddDependencyScoped<ModelDependencies>()
                  .AddDependencyScoped<ModelCreationDependencies>()
                  .AddDependencyScoped<AdHocMapperDependencies>();
      
              ServiceCollectionMap.TryAddSingleton<IRegisteredServices>(
                  new RegisteredServices(ServiceCollectionMap.ServiceCollection.Select(s => s.ServiceType)));
      
              return this;
          }

       

      DbContext 對象在初始化時只是查找實體集合,此時還沒有任何查詢被執行。當咱們要訪問實體數據時,DbSet<> 會把查詢任務交給 IAsyncQueryProvider 接口的實現類去處理,它的內部實現類是 EntityQueryProvider。

      EntityQueryProvider 內部基于 LINQ 生成表達式樹,表達式樹傳遞給 IQueryCompiler 去編譯并運行。IQueryCompiler 接口有個內部實現類叫 QueryCompiler。

      后面就一路往下傳遞到數據庫層,執行生成的SQL。當然這里頭還包含很多復雜的組件,此處咱們就不繼續挖,否則要挖到明天早上。

       

      本文老周只講述了和 DbContext 類添加實體集合相關的組件,其他組件等后面說到相關內容再介紹。咱們總不能一口氣把整個框架都說一遍的,太復雜了。

       

      posted @ 2025-06-29 22:31  東邪獨孤  閱讀(1687)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 年辖:市辖区| 人妻人人澡人人添人人爽人人玩| 中文字幕色av一区二区三区| 亚洲熟妇无码八av在线播放| 国产一区二区三区的视频| 人妻系列无码专区69影院| 国产精品高清视亚洲中文| 中文字幕国产精品自拍| 中国CHINA体内裑精亚洲日本| 亚洲中文字幕人成影院| 国产极品美女网站在线观看| 自拍第一区视频在线观看| 国产福利社区一区二区| 久久亚洲私人国产精品| 久久精品免费自拍视频| 一本一本久久A久久精品综合不卡| 永顺县| 四虎永久免费很黄的视频| 中国CHINA体内裑精亚洲日本| 国产成人久久777777| 久久天天躁夜夜躁狠狠躁2022| 国产在线观看播放av| 久久无码av中文出轨人妻| 熟女在线视频一区二区三区| 少妇高潮水多太爽了动态图| 国产不卡一区二区四区| 亚洲乱理伦片在线观看中字| 国产短视频一区二区三区| 欧美做受视频播放| 久久人人97超碰国产精品| 久久国产精品久久久久久| 国产高颜值不卡一区二区| 人妻日韩精品中文字幕| 欧美大胆老熟妇乱子伦视频| 国产午夜91福利一区二区| 丁香五月亚洲综合在线国内自拍| 国色天香中文字幕在线视频| 国产亚洲国产精品二区| 99精品国产中文字幕| 91精品国产自产在线蜜臀| 十八禁午夜福利免费网站|