3

私はEntityFrameworkCodeFirstを使用してマルチテナントアプリケーションを開発しています。各テナントはデータベース内に異なるスキーマを持ちますが、アプリケーションはすべてのテナントに対して単一のコンテキストとモデルを持ちます。

Entity Framwork 6は、同じデータベース内の複数のコンテキストで複数のスキーマを使用できますが、単一のコンテキストで複数のスキーマを使用する方法が見つかりませんでした。

デフォルトの「dbo」スキーマへの移行を(コマンドラインで)生成しました。これらの移行を使用して他のスキーマを更新したいと思います。

4

4 に答える 4

2

複数のコンテキストが絶対に良い方法であることに同意しますが(そして、私が独自のプロジェクトをセットアップする方法です)、単一のコンテキストで複数のスキーマを使用する方法に関する最初の質問に答えたいと思いました。

各モデルのマッピング構成内で、「ToTable(myTableName, mySchema)」を呼び出して、テーブルが属するスキーマを変更できます。

public class MyEntityMap : EntityTypeConfiguration<MyEntity>
{
    public MyEntityMap ()
    {
        HasKey(t => t.MyId);
        Property(t => t.MyId)
            .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);

        ToTable("MyEntity", "MySchema");
    }
}

これにより、単一のコンテキストを維持しながら、各テーブルのスキーマを個別に設定できます。

異なるスキーマで同じモデルを使用したいと述べたので、セットアップについて詳しく知らないと、少し難しくなります。少数の顧客のみを扱っており、スキーマをコードで維持することを気にしない場合は、スキーマごとに (上記のように) マップを作成し、顧客ごとに新しい DbSet を追加するだけです。これを多数の顧客に拡張しようとしている場合は、別のアプローチを検討することを強くお勧めします。なぜなら、各テーブルで customerID 列を使用するのではなく、異なるスキーマで 100 以上の同一のテーブルを見たときにデータベース管理者が叫ぶ可能性があるからです。 .

于 2013-07-16T20:41:30.040 に答える
1

こういった投稿を見ると

http://thedatafarm.com/data-access/digging-in-to-multi-tenant-migrations-with-ef6-alpha/

http://romiller.com/2011/05/23/ef-4-1-multi-tenant-with-code-first/

私はこの文脈を思いついた

public class DataLayerBuilder : DbContext
{
    private static  string conStr = string.Empty ;
    private DataLayerBuilder(DbConnection connection, DbCompiledModel model)
    : base(connection, model, contextOwnsConnection: false){ }
    public DbSet<Person> People { get; set; }

    private static ConcurrentDictionary<Tuple<string, string>, DbCompiledModel> modelCache
        = new ConcurrentDictionary<Tuple<string, string>, DbCompiledModel>();

    /// <summary>
    /// Creates a context that will access the specified tenant
    /// </summary>
    public static DataLayerBuilder Create(string tenantSchema)
    {
        conStr = ConfigurationManager.ConnectionStrings["ConnSTRName"].ConnectionString;
        var connection = new SqlConnection(conStr);
        var compiledModel = modelCache.GetOrAdd(
            Tuple.Create(conStr, tenantSchema),
            t =>
            {

                var builder = new DbModelBuilder();
                builder.HasDefaultSchema(tenantSchema);
                builder.Entity<Person>().ToTable("People");                   
                builder.Entity<Contact>().ToTable("Contacts");
                var model = builder.Build(connection);
                return model.Compile();
            });

        return new DataLayerBuilder(connection, compiledModel);
    }

    /// <summary>
    /// Creates the database and/or tables for a new tenant
    /// </summary>
    public static void ProvisionTenant(string tenantSchema)
    {
        try
        {
            using (var ctx = Create(tenantSchema))
            {
                if (!ctx.Database.Exists())
                {
                    ctx.Database.Create();
                }
                else
                {
                    ctx.Database.Initialize(true);

                }
            }
        }
        catch (Exception)
        {

            throw;
        }
    }
}

これまでのところ、次のコードを使用して複数のテナントを追加できました

 public void ProvisionTest()
    {
        //Arrange
        var tenant = "test2";

        //Act
        DataLayerBuilder.ProvisionTenant(tenant);

    }
}

上記のコードを改善すると、単純な関数を記述して、各ユーザーのテーブル構造を更新できると思います

これが役立つことを願っています

于 2014-10-28T20:37:46.543 に答える
0

このソリューションは、おそらく、Robert Petz と alfkonne の両方の回答と、接続管理と移行管理に関するいくつかのツールを組み合わせたものとして最もよく見られます。顧客固有のバックアップの目的で、顧客ごとのスキーマではなく DB レベルを好みます。スキーマ固有のバックアップ/復元 IF セットアップを適切に実行できます。ただし、関連する外部ツールがスキーマ ベースの復元に対応していることを確認してください。

于 2014-10-28T21:13:12.860 に答える