deezus blog

.Net Core、Typescriptを中心に技術的ノウハウを公開しています

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

はじめに

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

構成

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

共通データベース

顧客一覧テーブル(customers)

カラム名 備考
id int pk
name nvarchar(100)
dbname nvarchar(100) 接続文字列

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

商品テーブル(items)

カラム名 備考
id int pk
name nvarchar(100)
price int

処理の流れ

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

    }
}