实体框架核心中的动态变化模式 [英] Dynamically changing schema in Entity Framework Core

查看:121
本文介绍了实体框架核心中的动态变化模式的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个与EF Core合作的问题。我想通过模式机制分离我的项目数据库中不同公司的数据。我的问题是如何在运行时更改模式名称?我发现类似问题关于这个问题,但仍然没有得到答复,我有一些不同的条件。所以我有解决方法,在必要时提供数据库上下文

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

我可以在 OnModelCreating ,但是,如之前发现的,此方法只调用一次,因此我可以在这里设置模式名globaly,如下

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

或在模型中通过类似的

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

但是如何在运行时更改模式名称?我每个请求创建ef的上下文,但是首先,我通过请求向用户发送模式名称到数据库中的一些模式共享表。那么组织这个机制的真正方法是什么?


  1. 根据用户的凭据计算出模式名称;


谢谢。



PS我使用PostgreSql,这是表格名称较低的原因。

解决方案

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



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

 使用系统; 
使用Microsoft.EntityFrameworkCore;
使用Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal;
使用Microsoft.Extensions.Options;

命名空间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);

//此块强制映射方法调用每个实例
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。



MapProduct方法的定义:

 使用系统; 
使用Microsoft.EntityFrameworkCore;

命名空间AdventureWorksAPI.Models
{
public static class ProductMap
{
public static ModelBuilder MapProduct(此ModelBuilder modelBuilder,String模式)
{
var entity = modelBuilder.Entity< Product>();

entity.ToTable(Product,schema);

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

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

return modelBuilder;
}
}
}

如上图所示,有一行为表格设置模式和名称,您可以在DbContext中为一个构造函数发送模式名称或类似的东西。



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

  using System; 

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

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

  var humanResourcesDbContext = new AdventureWorksDbContext(Schemas.HumanResources); 

var productionDbContext = new AdventureWorksDbContext(Schemas.Production);

显然,您应该根据模式名称参数的值设置模式名称:

  entity.ToTable(Product,schemaName); 


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 schema name in runtime? I've found similar question about this issue but it's still ananswered and I have some different conditions. So I have Resolve method that grants db-context when necessary

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

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

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

or right in model via attribute like that

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

But how can I change schema name in runtime? I create ef's context per each request, but firstly I fugure out schema-name for user via request to some schema-shared table in database. So what is the true-way to organize that mechanism:

  1. Figure out schema name by user's credentials;
  2. Get user-specific data from database from specific schema.

Thank you.

P.S. I use PostgreSql and this is a reason of lowecased table name.

解决方案

Did you already use EntityTypeConfiguration in EF6?

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);
        }
    }
}

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

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;
        }
    }
}

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 = "Production";
}

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

var humanResourcesDbContext = new AdventureWorksDbContext(Schemas.HumanResources);

var productionDbContext = new AdventureWorksDbContext(Schemas.Production);

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

entity.ToTable("Product", schemaName);

这篇关于实体框架核心中的动态变化模式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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