【问题标题】:How to change database schema on runtime in EF7 or EF core如何在 EF7 或 EF 核心中更改运行时的数据库架构
【发布时间】:2016-05-12 07:44:27
【问题描述】:

根据用户在运行时的选择,我的数据库有不同的架构。

我的代码如下:

public partial class FashionContext : DbContext
{
    private string _schema;

    public FashionContext(string schema) : base()
    {
        _schema = schema;
    }

    public virtual DbSet<Style> Styles { get; set; }

    protected override void OnConfiguring(DbContextOptionsBuilder options)
    {
        options.UseSqlServer(@"Server=.\sqlexpress;Database=inforfashionplm;Trusted_Connection=True;");
    }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Style>()
            .ToTable("Style", schema: _schema);
    }
}

经测试。我用'schema1'创建了一个上下文实例。 到目前为止,一切都很好。

但是当我创建另一个具有不同架构“schema2”的上下文实例时,架构仍然在“schema1”上的结果数据。

这里是实现:

using (var db = new FashionContext("schema1"))
        {
            foreach (var style in db.Styles)
            {
                Console.WriteLine(style.Name);
            }
        }

        Console.ReadLine();
        Console.Clear();

        using (var db = new FashionContext("schema2"))
        {
            foreach (var style in db.Styles)
            {
                Console.WriteLine(style.Name);
            }
        }

        Console.ReadLine();

后来我注意到 OnModelCreating 只被调用一次,所以当你创建一个相同连接字符串的新上下文实例时,它就再也不会被调用了。

是否可以在运行时使用动态架构?注意:这在 EF6 中是可能的

【问题讨论】:

    标签: entity-framework


    【解决方案1】:

    上面提到了一种可能的方式,但很简短,所以我将尝试用例子来解释。

    您应该覆盖默认的 ModelCacheKeyFactoryModelCacheKey

    ModelCachekeyFactory.cs

    internal sealed class CustomModelCacheKeyFactory<TContext> : ModelCacheKeyFactory
        where TContext : TenantDbContext<TContext>
    {
        public override object Create(DbContext context)
        {
            return new CustomModelCacheKey<TContext>(context);
        }
    
        public CustomModelCacheKeyFactory([NotNull] ModelCacheKeyFactoryDependencies dependencies) : base(dependencies)
        {
        }
    }
    

    ModelCacheKey.cs,请查看 Equals 和 GetHashCode 覆盖的方法,它们不是最好的方法,应该改进。

    internal sealed class ModelCacheKey<TContext> : ModelCacheKey where TContext : TenantDbContext<TContext>
    {
        private readonly string _schema;
        public ModelCacheKey(DbContext context) : base(context)
        {
            _schema = (context as TContext)?.Schema;
        }
    
        protected override bool Equals(ModelCacheKey other)
        {
            return base.Equals(other) && (other as ModelCacheKey<TContext>)?._schema == _schema;
        }
    
        public override int GetHashCode()
        {
            var hashCode = base.GetHashCode();
            if (_schema != null)
            {
                hashCode ^= _schema.GetHashCode();
            }
    
            return hashCode;
        }
    }
    

    在 DI 注册。

    builder.UseSqlServer(dbConfiguration.Connection)
    .ReplaceService<IModelCacheKeyFactory, CustomModelCacheKeyFactory<CustomContext>>();
    

    上下文示例。

    public sealed class CustomContext : TenantDbContext<CustomContext>
    {
        public CustomContext(DbContextOptions<CustomContext> options, string schema) : base(options, schema)
        {
        }
    }
    

    【讨论】:

    • 如果你使用同一个类似乎不起作用。我正在使用带有架构名称作为属性的自定义 DbContext。架构名称会根据域而变化。无论我是否切换域,它仍然只使用一种模式。自定义 ModelCacheKey 只调用一次。
    【解决方案2】:

    您可以在外部构建模型并使用DbContextOptionsBuilder.UseModel() 将其传递到DbContext

    另一种(更高级的)替代方法是替换 IModelCacheKeyFactory 以考虑架构。

    【讨论】:

      【解决方案3】:

      我找到了一种在每次创建上下文时重新创建已编译模型的方法。

      public partial class MyModel : DbContext {
      
          private static DbConnection _connection
          {
              get
              {
                  //return a new db connection
              }
          }
      
          private static DbCompiledModel _model
          {
              get
              {
                  return CreateModel("schema name");
              }
          }
      
          public MyModel()
              : base(_connection, _model, false)
          {
          }
      
          private static DbCompiledModel CreateModel(string schema)
          {
              var modelBuilder = new DbModelBuilder();
              modelBuilder.HasDefaultSchema(schema);
              modelBuilder.Entity<entity1>().ToTable(schema + ".entity1");
              var builtModel = modelBuilder.Build(_connection);
              return builtModel.Compile();
          }
      }
      

      【讨论】:

      • 这个问题是关于 EF Core,但你的答案是针对 EF6。这可能就是它被否决的原因。
      猜你喜欢
      • 1970-01-01
      • 2023-01-18
      • 2019-10-25
      • 1970-01-01
      • 2017-01-14
      • 1970-01-01
      • 2023-03-13
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多