EntityFrameworkCoreで接続文字列を動的に変更する方法

.Net Core

はじめに

ASP.NET Core + EntityFrameworkCore製マルチテナントのシステムで顧客ごとにデータベースが分かれており、動的に接続文字列を切り替える必要がある場合の対処法

構成

下記のようなデータベース構造を想定します

共通データベース

顧客一覧テーブル(customers)

カラム名備考
idintpk
namenvarchar(100) 
dbnamenvarchar(100)接続文字列

各顧客データベース(顧客ごとに存在)

商品テーブル(items)

カラム名備考
idintpk
namenvarchar(100) 
priceint 

処理の流れ

  1. 共通データベースのcustomerからdbnameを取得
  2. dbnameで各顧客データベースに接続し、itemsからデータを取得する

実装例

DbContext

各テーブルのエンティティを下記のように定義し、DbContextを継承したクラスを作成します
接続先データベースごとにDbContextを分割しています

[Table("customers")]
public class Customer
{
    [Key]
    [Column("id")]
    public int Id { get; set; }
        
    [Column("name")]
    public string Name { get; set; }

    [Column("dbname")]
    public string DbName{get;set; }
}

[Table("items")]
public class Item
{
    [Key]
    [Column("id")]
    public int Id { get; set; }
        
    [Column("name")]
    public string Name { get; set; }

    [Column("price")]
    public int price {get;set; }
}


public class ShareContext : DbContext
{
    public DbSet<Customer> Customers { get; set; }

     public Context(DbContextOptions<ShareContext > options) : base(options)
     {
            
     }
}

public class CustomerContext : DbContext
{
    public DbSet<Item> Items { get; set; }

     public Context(DbContextOptions<CustomerContext> options) : base(options)
     {
            
     }
}

Startup.csのConfigureServicesメソッドでDIする

// 共通データベースに接続するShareContext
var sb = new SqlConnectionStringBuilder {DataSource = "localhost", UserID = "sa", Password = "!Passw0rd", InitialCatalog = "share"};
services.AddDbContext<ShareContext>(op => { op.UseSqlServer(sb.ToString()); });

// 各顧客データベースに接続するCustomerContext
services.AddDbContext<CustomerContext>(op => { op.UseSqlServer(sb.ToString()); });

Controllerで使用する

public class HomeController : Controller
{
    public HomeController(ShareContext shareContext, CustomerContext customerContext)
    {
        // 接続文字列取得
        var customer = shareContext.Customers.Find(1);

        // 接続文字列を設定
       customerContext.Database.GetDbConnection().ConnectionString = customer.DbName;

       // データ取得
       var items = customerContext.Items.ToList();

    }
}
タイトルとURLをコピーしました