在 Entity Framework Core 中动态更改架构 [英] Dynamically changing schema in Entity Framework Core

查看:27
本文介绍了在 Entity Framework Core 中动态更改架构的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

UPD 这里是我解决问题的方法.虽然它可能不是最好的,但它对我有用.

UPD here is the way I solved the problem. Although it's likely to be not the best one, it worked for me.

我在使用 EF Core 时遇到问题.我想通过模式机制将项目数据库中不同公司的数据分开.我的问题是如何在运行时更改架构名称?我发现了类似的问题 关于这个问题,但仍然没有答案,我有一些不同的情况.所以我有 Resolve 方法可以在必要时授予 db-context

I have an issue with working with EF Core. I want to separate data for different companies in my project's database via schema-mechanism. My question is how I can change the schema name in runtime? I've found similar question about this issue but it's still unanswered and I have some different conditions. So I have the Resolve method that grants the db-context when necessary

public static void Resolve(IServiceCollection services) {
    services.AddIdentity<ApplicationUser, IdentityRole>()
        .AddEntityFrameworkStores<DomainDbContext>()
        .AddDefaultTokenProviders();
    services.AddTransient<IOrderProvider, OrderProvider>();
    ...
}

我可以在 OnModelCreating 中设置模式名,但是,正如之前发现的,这个方法只调用一次,所以我可以像这样全局设置模式名

I can set the schema-name in OnModelCreating, but, as was found before, this method is called just once, so I can set schema name globaly like that

protected override void OnModelCreating(ModelBuilder modelBuilder) {
    modelBuilder.HasDefaultSchema("public");
    base.OnModelCreating(modelBuilder);
}

或通过属性直接在模型中

or right in the model via an attribute

[Table("order", Schema = "public")]
public class Order{...}

但是如何在运行时更改架构名称?我为每个请求创建上下文,但首先我通过对数据库中模式共享表的请求计算出用户的模式名称.那么组织该机制的正确方法是什么:

But how can I change the schema name on runtime? I create the context per each request, but first I fugure out the schema-name of the user via a request to a schema-shared table in the database. So what is the right way to organize that mechanism:

  1. 根据用户凭据找出架构名称;
  2. 从特定架构的数据库中获取特定于用户的数据.

谢谢.

附言我使用 PostgreSql,这就是表名小写的原因.

P.S. I use PostgreSql and this is the reason for lowecased table names.

推荐答案

您是否已经在 EF6 中使用了 EntityTypeConfiguration?

Did you already use EntityTypeConfiguration in EF6?

我认为解决方案是在 DbContext 类中的 OnModelCreating 方法上使用实体映射,如下所示:

I think the solution would be use mapping for entities on OnModelCreating method in DbContext class, something like this:

using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal;
using Microsoft.Extensions.Options;

namespace AdventureWorksAPI.Models
{
    public class AdventureWorksDbContext : Microsoft.EntityFrameworkCore.DbContext
    {
        public AdventureWorksDbContext(IOptions<AppSettings> appSettings)
        {
            ConnectionString = appSettings.Value.ConnectionString;
        }

        public String ConnectionString { get; }

        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            optionsBuilder.UseSqlServer(ConnectionString);

            // this block forces map method invoke for each instance
            var builder = new ModelBuilder(new CoreConventionSetBuilder().CreateConventionSet());

            OnModelCreating(builder);

            optionsBuilder.UseModel(builder.Model);
        }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.MapProduct();

            base.OnModelCreating(modelBuilder);
        }
    }
}

OnConfiguring 方法上的代码强制在 DbContext 类的每个实例创建时执行 MapProduct.

The code on OnConfiguring method forces the execution of MapProduct on each instance creation for DbContext class.

MapProduct 方法的定义:

Definition of MapProduct method:

using System;
using Microsoft.EntityFrameworkCore;

namespace AdventureWorksAPI.Models
{
    public static class ProductMap
    {
        public static ModelBuilder MapProduct(this ModelBuilder modelBuilder, String schema)
        {
            var entity = modelBuilder.Entity<Product>();

            entity.ToTable("Product", schema);

            entity.HasKey(p => new { p.ProductID });

            entity.Property(p => p.ProductID).UseSqlServerIdentityColumn();

            return modelBuilder;
        }
    }
}

正如你在上面看到的,有一行设置表的模式和名称,你可以在 DbContext 或类似的东西中为一个构造函数发送模式名称.

As you can see above, there is a line to set schema and name for table, you can send schema name for one constructor in DbContext or something like that.

请不要使用魔法字符串,您可以创建一个包含所有可用模式的类,例如:

Please don't use magic strings, you can create a class with all available schemas, for example:

using System;

public class Schemas
{
    public const String HumanResources = "HumanResources";
    public const String Production = "Production";
    public const String Sales = "Sales";
}

要创建具有特定架构的 DbContext,您可以这样写:

For create your DbContext with specific schema you can write this:

var humanResourcesDbContext = new AdventureWorksDbContext(Schemas.HumanResources);

var productionDbContext = new AdventureWorksDbContext(Schemas.Production);

显然你应该根据schema的name参数的值来设置schema名称:

Obviously you should to set schema name according schema's name parameter's value:

entity.ToTable("Product", schemaName);

这篇关于在 Entity Framework Core 中动态更改架构的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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