Entity Framework Core でスキーマを動的に変更する 質問する

Entity Framework Core でスキーマを動的に変更する 質問する

上院 こここれは私が問題を解決した方法です。おそらく最善の方法ではないかもしれませんが、私にとってはうまくいきました。


EF Coreの使用で問題があります。プロジェクトのデータベースで、スキーマメカニズムを使用して異なる会社のデータを分離したいと考えています。私の質問は、実行時にスキーマ名を変更する方法です。同様の質問この問題についてですが、まだ回答が得られておらず、いくつかの異なる条件があります。そのため、Resolve必要に応じてdb-contextを許可する方法があります

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

でスキーマ名を設定できますOnModelCreatingが、前に述べたように、このメソッドは一度だけ呼び出されるので、次のようにスキーマ名をグローバルに設定できます。

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

または属性を介してモデルに直接

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

しかし、実行時にスキーマ名を変更するにはどうすればよいでしょうか。リクエストごとにコンテキストを作成しますが、まずデータベース内のスキーマ共有テーブルへのリクエストを介してユーザーのスキーマ名を調べます。では、そのメカニズムを整理する正しい方法は何でしょうか。

  1. ユーザー資格情報からスキーマ名を特定します。
  2. 特定のスキーマからデータベースからユーザー固有のデータを取得します。

ありがとう。

PS 私は PostgreSql を使用していますが、これがテーブル名が小文字になっている理由です。

ベストアンサー1

EF6 で既に EntityTypeConfiguration を使用しましたか?

解決策としては、DbContext クラスの OnModelCreating メソッドでエンティティのマッピングを使用することだと思います。次のようになります。

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 の実行を強制します。

MapProduct メソッドの定義:

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 などの 1 つのコンストラクターにスキーマ名を送信できます。

マジック ストリングを使用しないでください。使用可能なすべてのスキーマを含むクラスを作成できます。次に例を示します。

using System;

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

特定のスキーマを使用して DbContext を作成するには、次のように記述します。

var humanResourcesDbContext = new AdventureWorksDbContext(Schemas.HumanResources);

var productionDbContext = new AdventureWorksDbContext(Schemas.Production);

当然のことながら、スキーマの名前パラメータの値に応じてスキーマ名を設定する必要があります。

entity.ToTable("Product", schemaName);

おすすめ記事