はじめに
ASP.NET Core + EntityFrameworkCore製マルチテナントのシステムで顧客ごとにデータベースが分かれており、動的に接続文字列を切り替える必要がある場合の対処法
構成
下記のようなデータベース構造を想定します
共通データベース
顧客一覧テーブル(customers)
カラム名 | 型 | 備考 |
---|---|---|
id | int | pk |
name | nvarchar(100) | |
dbname | nvarchar(100) | 接続文字列 |
各顧客データベース(顧客ごとに存在)
商品テーブル(items)
カラム名 | 型 | 備考 |
---|---|---|
id | int | pk |
name | nvarchar(100) | |
price | int |
処理の流れ
- 共通データベースのcustomerからdbnameを取得
- 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();
}
}