質問: Entity Framework Core 2.1とSQL Server 2017(Webエディション)を使用するASP.NET Core 2.1アプリケーションがあります。私は複数のテナントの問題を解決する方法をたくさん読んでいますが、答えは多かれ少なかれです: > それはあなたのアプリケーション、セットアップに依存します。 > > **セットアップ:** * すべてのクライアントはデータベース用の独自の設定で新しいIISサイトを取得します * テナント間で共有しなければならないいくつかのテーブル(クライアントがセットアップで定義するもの):たとえば、ユーザー、グループ、権限、ユーザー設定の共通テーブルがありますが、オファー、価格、イベントなどは別です。 * すべてのテーブルには主キーである識別列( `int` )があります * すべてのテナントは全く同じテーブル構造を持っています(クライアントをアップグレードするときは、すべてのテナントがすべてのテーブル構造を更新する必要があります) * 私はEFコアでコードファーストのアプローチを使用しています **オプション:** 1. すべてのクライアントおよびテナント用のデータベースを個別に作成する(Db名`client_tenant` ) 2. すべてのクライアント用にデータベースを分離し、テナント用にスキーマを使用する(Db名`client.tenant` ) 3. すべてのクライアントのデータベースを分離し、各テーブルの列を使用する( `TenantId` ) **詳細:** 私はすべてのオプションにコンプとプロがあることを知っているので、セットアップに関する詳細はこちらです: * すべてのクライアントに1人以上(最大1000人)のテナント(平均約20人) * テナント間でテーブルを共有する必要があります * 約500百のテーブルがあり、テナント(共有する必要のあるクライアント)の間で約10個が共有可能(共通)であり、 * 最大のテーブルは年間1000万レコードを生産することができます 私がそれらを見るように**長所/短所** : 1. 別個のデータベース(テナント用の別個のDB): * プロ + セキュリティ + テーブル構造の変更は、EF(移行)によって完全にサポートされています。 + テーブルは透明です * 短所 + データベースを動的に変更するのは簡単ではありません + EFコアによるデータベースへの左結合はまだサポートされていません*(次の点に関連して*います*)* + 共通テーブル(ユーザ、グループ、権利、ユーザーの設定)1を解決するためにどのように現時点では何も解決しません。 + 多くのデータベース: `client1_tenant1` 、 `client1_tenant2` 、...、 `client2_tenant1` ... 2. 別々のスキーム(1Db、テナント別のスキーム): * プロ + データの共有に問題はありません(私は共通テーブル用に1つのデフォルトスキーマを持つことができます) + 安全な(1より小さいオプション) * 短所 + 動的にスキーマを変更するのは簡単ではない + 私はモジュール内のテーブルを分離するためにスキーマを使用することはできません + EF 2でテーブル構造の変更を管理する 3. `TenantId`列(1 Db、1スキーム): * プロ + EFコアで完全サポート - グローバルクエリフィルタ 、マイグレーション... * 短所 + 非常に大きなテーブルを持つことができます(1クライアント* 500テナント* 2000000レコード* 10年= 10年で100億行 - 最大のクライアント、最大のテーブル) + セキュリティ3 + 潜在的なパフォーマンス上の問題 + 維持しにくい(非常に大きなテーブル - 透明ではない) **概要:** 私が次のような場合に、どのアプローチを選択すべきですか(1,2、または3) * EFコアを使用しています * テナント間でいくつかのテーブルを共有する必要があります(同期は1分以内に起こるはずです)。 4 * 非常に大きなテーブルを持つことができます * 私は500以上のテーブルを持っていて、論理的には1つのモジュールに属しています **関連トピック:(**私が宿題をして、重複を検索したことを証明するだけ**です** ) * 異なるデータベースに2つのテーブルを同期: 1 、 2を * マルチテナント - EF 6の最初のコード(コアではない) * 複数のDbスキーマによる移行 * 非常に異なるセットアップで同じ質問 * 多くの多くの、私は問題と可能な解決策をよりよく理解できるように **参考文献:** 1 1つの方法は、 SQL Serverのレプリケーションです。 各クライアントには、テナントが見ることができる、編集する、設定する列についての権利を管理するためのいくつかの共通テーブルがあります。 2これが可能なのかどうかはわかりません。おそらく私は`for`ループを呼び出すべき`context.Database.Migrate();`すべてのテナントのために。 3すべてのデータが同じテーブルに属しているため、あるテナントが別のテナントのデータを参照するバグはひどいが、壊滅的ではありません。また、 グローバルなフィルタリングによって、このリスクは最小化されます。 4これらの変更はあまり頻繁に起こらないので、コードの変更を同期させるためのAPI(バックグラウンドスレッド)を書くことができます。
回答: > そうです、あなたのアプリケーションによって異なります。 > > 私は1で行くだろう。 > テナント間で共有されなければならないテーブル(クライアントはセットアップで定義するもの)があります。たとえば、ユーザー、グループ、権限、ユーザー設定の共通テーブルがありますが、オファー、価格、イベント > > 設定、ユーザー管理、グループ、権限などのテーブルが必要な場合は、クライアントごとに個別のデータベースを作成する必要があります.1つの目的は、ユーザーの処理 - crud、rights、groups、checksなどです。 この情報は、クレームまたは他の適切な認証システムとして渡す必要があります。 ですから、私はclient1_user_management、client1_tenant1、client1_tenant2などのように作成します あなたがクレーム(jwt、クッキー)または他の方法でグループ、権利などを渡すために使用している場合は`left join with EF Core over databases`必要はありません。私が間違っているなら私を訂正してください。 他の詐欺に関して: `not so easy to dynamically change database` 。 このような構成を避けるために、サブドメインなどに基づいてデータベースを注入することができます。 ``` public void Configure() { Dictionary connStrs = new Dictionary(); connStrs.Add("DB1", Configuration["Data:DB1Connection:ConnectionString"]); connStrs.Add("DB2", Configuration["Data:DB2Connection:ConnectionString"]); DbContextFactory.SetConnectionString(connStrs); } ``` おそらく、複数のクライアント/複数のテナントを処理する1つのアプリケーションがあります。リクエストごとに1人のクライアントと1人のテナントを特定して注入すると便利です。 https://client1.myapp.com/tenant1- >私はclient1とtenant1を識別できます。私はデータベース名(client1_tenant1のようにハードコードされているか、テナント管理システムを持っている場合は設定されています)を見つけることができます。私はデータベース名を知ることができるので、私はそれを使って`DBContext`ごとに`DBContext`を作成します(スコープ付き: Asp.Net Coreのservices.AddTransient、service.AddScopeとservice.AddSingletonメソッドの違いは何ですか? )。 PS:これは現在の情報に基づく意見です。可能であれば、私はこの解決策を推進しようとします。