如何禁用实体框架6中的模型缓存(Code First方法) [英] How to disable model caching in Entity Framework 6 (Code First approach)

查看:752
本文介绍了如何禁用实体框架6中的模型缓存(Code First方法)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

以下 MSDN文档,我们可以看到:


然后,该上下文的模型被缓存,适用于上下文的所有其他实例在应用程式的网域。 可以通过在给定的ModelBuidler 上设置ModelCaching属性来禁用此缓存,但请注意,这可能严重降低性能。

The model for that context is then cached and is for all further instances of the context in the app domain. This caching can be disabled by setting the ModelCaching property on the given ModelBuidler, but note that this can seriously degrade performance.

问题是模型构建器不包含名为 ModelCaching 的任何属性。

The problem is the model builder does not contain any property named ModelCaching.

如何禁用模型缓存例如,在运行时更改模型配置)?

How it is possible to disable the model caching (e.g. for changing model configuration in a run-time)?

推荐答案

向前警告:不用说,下面所示的机制只要您不需要执行来自不同上下文的表之间的连接即可覆盖您的需求。如果您需要这样的操作,那么您将不得不使用小型API进一步细化下面所示的机制,以便您可以将所有表与一些字符串或数字动态关联(以便您可以在运行时随意访问和组合各自的DBSets) 。做这样的事情 - 更普遍 - 有点复杂,超出了这个答案的范围。

Forward Warning: It goes without saying that the mechanism shown below will cover your needs as long as you don't need to perform joins between tables that come from different contexts. If you need such operations then you will have to further refine the mechanism shown below with a small API so that you can dynamically associate said tables with some string or number (so that you may access and combine their respective DBSets dynamically at will in runtime). Doing this sort of thing -altough more general- is a bit complex and falls outside the scope of this answer.

这是一个全面实施的机制, bairog - 所有的信用给他。请注意,我们通过新的DbContext获取与数据库的连接,原因是在注释中解释:

Here's a full-blown implementation of the mechanism put forward by bairog - all credit goes to him. Notice that we get the connection to the database via new DbContext for reasons explained in the comments:

     using System;
     using System.Collections.Concurrent;
     using System.ComponentModel.DataAnnotations;
     using System.Data.Common;
     using System.Data.Entity;
     using System.Data.Entity.Infrastructure;
     using System.Data.Entity.ModelConfiguration;

     namespace Utilities
     {
         // usage:
         //
         // var context1 = new FooContext("Schema1", "PingTable1", "PongTable1");
         // context1.Ping.Select(x => x.Id > 10).ToList();     
         // context1.Pong.Select(x => x.Id > 20).ToList();

         public class FooContext : DbContext
         {
             public DbSet<Ping> Ping { get; set; }
             public DbSet<Pong> Pong { get; set; }

             static public FooContext Spawn(string nameOrConnectionString, string pingTablename, string pongTablename, string schemaName = null) //minifactory
             {
                 //if (string.IsNullOrWhiteSpace(schemaName?.Trim())) throw new ArgumentException(nameof(schemaName)); //canbe
                 if (string.IsNullOrWhiteSpace(pingTablename?.Trim())) throw new ArgumentException(nameof(pingTablename));
                 if (string.IsNullOrWhiteSpace(pongTablename?.Trim())) throw new ArgumentException(nameof(pongTablename));

                 var dummyDbContext = new DbContext(nameOrConnectionString); //0 stupidhack for retrieving the connection

                 return new FooContext(dummyDbContext, GetModelBuilderAndCacheIt(dummyDbContext.Database.Connection, pingTablename, pongTablename, schemaName));
             }
             //0 stupidhack over EntityConnection("name=NameOfConnectionStringFromWebConfig") which wasnt working because it demands metadata on the
             //  codefirst connection to an oracle db (at least oracledb ver11 - go figure ...)
             //
             //  update: I finally had success using the *managed* driver oracle.manageddataaccess with oracle-odac ver12+    one may now use:
             //
             //  var connectionString = ConfigurationManager.ConnectionStrings[nameOrConnectionString];
             //  if (connectionString == null) return null;
             //  
             //  var factory = DbProviderFactories.GetFactory(connectionString.ProviderName);
             //  var connection = factory.CreateConnection();
             //  connection.ConnectionString = connectionString.ConnectionString; //vital
             //  
             //  new FooContext(dummyDbContext, GetModelBuilderAndCacheIt(connection, pingTablename, pongTablename, schemaName));

             private static readonly object DbCompiledModelRegistrarLocker = new object(); // ReSharper disable InconsistentlySynchronizedField
             private static readonly ConcurrentDictionary<Tuple<string, string, string>, DbCompiledModel> DbModelBuilderCache = new ConcurrentDictionary<Tuple<string, string, string>, DbCompiledModel>();

             static private DbCompiledModel GetModelBuilderAndCacheIt(DbConnection databaseConnection, string pingTablename, string pongTablename, string schemaName) //0
             {
                 var key = Tuple.Create(pingTablename, pongTablename, schemaName);
                 if (DbModelBuilderCache.ContainsKey(key))
                     return DbModelBuilderCache[key];

                 lock (DbCompiledModelRegistrarLocker)
                 {
                     if (DbModelBuilderCache.ContainsKey(key))
                         return DbModelBuilderCache[key];

                     var modelBuilder = new DbModelBuilder();
                     modelBuilder.Configurations.Add(new PingFluentConfiguration(schemaName, pingTablename));
                     modelBuilder.Configurations.Add(new PongFluentConfiguration(schemaName, pongTablename));

                     //setting a maxsize for the cache so that least used dbmodels get flushed away is left as an exercise to the reader
                     return DbModelBuilderCache[key] = modelBuilder.Build(databaseConnection).Compile();
                 }
             }

             //0 building the same model over and over is very expensive operation and this is why we resorted to caching the modelbuilders
             // ReSharper restore InconsistentlySynchronizedField

             private DbContext _dummyDbContext;

             private FooContext(DbContext dummyDbContext, DbCompiledModel compiledModel)
                 : base(dummyDbContext.Database.Connection, compiledModel, contextOwnsConnection: true)
             {
                 _dummyDbContext = dummyDbContext;

                 Database.SetInitializer<FooContext>(strategy: null); //0
             }

             //0 http://stackoverflow.com/a/39710954/863651   ef by default attempts to create the database if it doesnt exist
             //  however in this case we want ef to just do nothing if the underlying database doesnt exist

             //protected override void OnModelCreating(DbModelBuilder modelBuilder) //0 here be dragons   beware that this approach wont work as intended down the road
             //{
             //    modelBuilder.Configurations.Add(new PingFluentConfiguration(_schemaName, _tablename)); //0 here be dragons   beware that this approach wont work as intended down the road
             //    base.OnModelCreating(modelBuilder);
             //}

             protected override void Dispose(bool disposing)
             {
                 if (disposing)
                 {
                     _dummyDbContext?.Dispose();
                     _dummyDbContext = null;
                 }

                 base.Dispose(disposing);
             }
         }

         public sealed class PingFluentConfiguration : EntityTypeConfiguration<Ping>
         {
             public PingFluentConfiguration(string schemaName, string tableName)
             {
                 HasKey(t => t.Id);

                 ToTable(schemaName: schemaName, tableName: tableName);
             }
         }

         public sealed class PongFluentConfiguration : EntityTypeConfiguration<Pong>
         {
             public PongFluentConfiguration(string schemaName, string tableName)
             {
                 HasKey(t => t.Id);

                 ToTable(schemaName: schemaName, tableName: tableName);
             }
         }

         public class Ping
         {
             [Key]
             [Required]
             public string Id { get; set; }

             [Required]
             public string Name { get; set; }
         }

         public class Pong
         {
             [Key]
             [Required]
             public string Id { get; set; }

             [Required]
             public string Name { get; set; }
         }
     }

这篇关于如何禁用实体框架6中的模型缓存(Code First方法)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆