【问题标题】:Entity Framework Core - Disable Model caching , call onModelCreating() for each instance dcontextEntity Framework Core - 禁用模型缓存,为每个实例调用 onModelCreating() dcontext
【发布时间】:2020-10-08 13:59:13
【问题描述】:

文档说:该上下文的模型已缓存,并且适用于应用程序域中上下文的所有进一步实例。可以通过在给定的 ModelBuidler 上设置 ModelCaching 属性来禁用此缓存

但我找不到办法。我必须禁用缓存,因为我在运行时添加模型并从程序集中加载所有模型并创建数据库。

我发现这个链接说实现这一点的一种方法是使用 DBModelBuilding - 手动将模型添加到上下文,但它适用于实体框架,对 EF Core 没有帮助。

Entity Framework 6. Disable ModelCaching

希望有人能解决这个问题。

谢谢

【问题讨论】:

    标签: c# entity-framework-core ef-code-first dotnetcorecli


    【解决方案1】:

    您需要change the cache key 才能正确表示您正在构建的模型/使其与众不同。

    1. 在派生的 DbContext 上实现 IDbModelCacheKeyProvider 接口。看一下这个 https://docs.microsoft.com/en-us/dotnet/api/system.data.entity.infrastructure.idbmodelcachekeyprovider?redirectedfrom=MSDN&view=entity-framework-6.2.0

    2. Build the model outside DbContext 然后provide it in the options

    【讨论】:

      【解决方案2】:

      成功创建模型后,EF Core 将永久缓存它,除非您实现的缓存管理器能够判断一个模型是否与另一个模型等效,因此它可以被缓存。

      入口点是实现缓存管理器:

      internal sealed class MyModelCacheKeyFactory : IModelCacheKeyFactory
      {
          public object Create([NotNull] DbContext context)
          {
              return GetKey(context);
          }
      }
      

      您必须编写的GetKey 方法必须返回一个将用作键的对象。此方法应检查提供的上下文并在模型相同时返回相同的键,而在模型不同时返回不同的键。更多关于IModelCacheKeyFactory Interface

      我明白,这可能不太清楚(我也不适合我),所以我写了一个完整的例子来说明我在生产中拥有的东西。

      一个工作示例

      我的目标是为不同的模式使用相同的上下文。我们需要做的是

      1. 创建一个新的上下文选项
      2. 在上下文中实现逻辑
      3. 创建缓存密钥工厂
      4. 制作扩展方法以指定架构
      5. 在 db 上下文中调用扩展方法

      1。创建一个新的上下文选项

      这里有一个仅包含_schemaName 的样板。样板文件是必要的,因为扩展选项在设计上是不可变的,我们需要保留合同。

      internal class MySchemaOptionsExtension : IDbContextOptionsExtension
      {
          private DbContextOptionsExtensionInfo? _info;
          private string _schemaName = string.Empty;
      
          public MySchemaOptionsExtension()
          {
          }
      
          protected MySchemaOptionsExtension(MySchemaOptionsExtension copyFrom)
          {
              _schemaName = copyFrom._schemaName;
          }
      
          public virtual DbContextOptionsExtensionInfo Info => _info ??= new ExtensionInfo(this);
      
          public virtual string SchemaName => _schemaName;
      
          public virtual void ApplyServices(IServiceCollection services)
          {
              // not used
          }
      
          public virtual void Validate(IDbContextOptions options)
          {
              // always ok
          }
      
          public virtual MySchemaOptionsExtension WithSchemaName(string schemaName)
          {
              var clone = Clone();
      
              clone._schemaName = schemaName;
      
              return clone;
          }
      
          protected virtual MySchemaOptionsExtension Clone() => new(this);
      
          private sealed class ExtensionInfo : DbContextOptionsExtensionInfo
          {
              private const long ExtensionHashCode = 741; // this value has chosen has nobody else is using it
      
              private string? _logFragment;
      
              public ExtensionInfo(IDbContextOptionsExtension extension) : base(extension)
              {
              }
      
              private new MySchemaOptionsExtension Extension => (MySchemaOptionsExtension)base.Extension;
      
              public override bool IsDatabaseProvider => false;
      
              public override string LogFragment => _logFragment ??= $"using schema {Extension.SchemaName}";
      
              public override long GetServiceProviderHashCode() => ExtensionHashCode;
      
              public override void PopulateDebugInfo([NotNull] IDictionary<string, string> debugInfo)
              {
                  debugInfo["MySchema:" + nameof(DbContextOptionsBuilderExtensions.UseMySchema)] = (ExtensionHashCode).ToString(CultureInfo.InvariantCulture);
              }
          }
      }
      

      2。上下文中的逻辑

      在这里,我们将架构强制用于所有真实实体。架构是通过附加到上下文的选项获得的

      protected override void OnModelCreating(ModelBuilder modelBuilder)
      {
         var options = this.GetService<IDbContextOptions>().FindExtension<MySchemaOptionsExtension>();
         if (options == null)
         {
             // nothing to apply, this is a supported scenario.
             return;
         }
      
         var schema = options.SchemaName;
      
         foreach (var item in modelBuilder.Model.GetEntityTypes())
         {
             if (item.ClrType != null)
                 item.SetSchema(schema);
         }
      }
      

      3。创建缓存密钥工厂

      这里我们需要创建缓存工厂,它将告诉 EF Core 它可以缓存同一上下文中的所有模型,即具有相同架构的所有上下文将使用相同的模型:

      internal sealed class MyModelCacheKeyFactory : IModelCacheKeyFactory
      {
          public object Create([NotNull] DbContext context)
          {
              const string defaultSchema = "dbo";
              var extension = context.GetService<IDbContextOptions>().FindExtension<MySchemaOptionsExtension>();
      
              string schema;
              if (extension == null)
                  schema = defaultSchema;
              else
                  schema = extension.SchemaName;
      
              if (string.IsNullOrWhiteSpace(schema))
                  schema = defaultSchema;
              // ** this is the magic **
              return (context.GetType(), schema.ToUpperInvariant());
          }
      }
      

      魔法就在这一行

      return (context.GetType(), schema.ToUpperInvariant());
      

      我们返回一个包含上下文类型和模式的元组。元组的哈希结合了每个条目的哈希,因此类型和模式名称是这里的逻辑鉴别符。当它们匹配时,模型被重用;如果没有,则会创建一个新模型,然后进行缓存。

      4。制作扩展方法

      扩展方法只是隐藏了选项的添加和缓存服务的替换。

      public static DbContextOptionsBuilder UseMySchema(this DbContextOptionsBuilder optionsBuilder, string schemaName)
      {
          if (optionsBuilder == null)
              throw new ArgumentNullException(nameof(optionsBuilder));
          if (string.IsNullOrEmpty(schemaName))
              throw new ArgumentNullException(nameof(schemaName));
      
          var extension = optionsBuilder.Options.FindExtension<MySchemaOptionsExtension>() ?? new MySchemaOptionsExtension();
      
          extension = extension.WithSchemaName(schemaName);
      
          ((IDbContextOptionsBuilderInfrastructure)optionsBuilder).AddOrUpdateExtension(extension);
      
          optionsBuilder.ReplaceService<IModelCacheKeyFactory, MyModelCacheKeyFactory>();
      
          return optionsBuilder;
      }
      

      特别是,以下行应用了我们的缓存管理器:

      optionsBuilder.ReplaceService<IModelCacheKeyFactory, MyModelCacheKeyFactory>();
      

      5。调用扩展方法

      您可以手动创建上下文,如下所示:

      var options = new DbContextOptionsBuilder<DataContext>();
      
      options.UseMySchema("schema1")
      options.UseSqlServer("connection string omitted");
      
      var context = new DataContext(options.Options)
      

      或者,您可以将IDbContextFactory 与依赖注入一起使用。更多关于IDbContextFactory Interface

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2023-03-03
        • 1970-01-01
        • 1970-01-01
        • 2022-01-01
        • 2019-05-12
        • 1970-01-01
        • 2020-04-27
        • 1970-01-01
        相关资源
        最近更新 更多