さて、これが私が現在持っているものです、それはマルチテナンシーを提供します、それはプラグインを提供します-清潔さ/優雅さはそれほど多くありません。
public class Context : DbContext
{
private static ConcurrentDictionary<string, DbCompiledModel> modelCache =
new ConcurrentDictionary<string, DbCompiledModel>();
private Context(DbCompiledModel model) : base(model)
{
}
public static Context Create(string tenantSchema)
{
var compiledModel = modelCache.GetOrAdd(
tenantSchema,
t =>
{
var providerInfo =
new DbProviderInfo("System.Data.SqlClient", "2008");
var modelBuilder = new DbModelBuilder();
modelBuilder.Conventions.Remove<IncludeMetadataConvention>();
foreach (var plugin in ServiceLocator
.Current
.GetAllInstances<IPlugin>().ToList())
{
plugin.SetupPersistence(modelBuilder,tenantSchema);
}
var model = modelBuilder.Build(providerInfo);
return model.Compile();
});
return new Context(compiledModel);
}
/// <summary>
/// Creates the database and/or tables for a new tenant
/// </summary>
public static void ProvisionTenant(string tenantSchema)
{
using (var ctx = Create(tenantSchema))
{
if (!ctx.Database.Exists())
{
ctx.Database.Create();
}
else
{
try
{
var createScript = ((IObjectContextAdapter)ctx)
.ObjectContext
.CreateDatabaseScript();
ctx.Database.ExecuteSqlCommand(createScript);
}
catch (Exception ex)
{
Console.WriteLine("Tenant already exists.");
}
}
}
}
}
プラグインは次のようになります。
[Export(typeof(IPlugin))]
public class Class2 : IPlugin
{
public int Id { get; set; }
public string Name { get; set; }
public string Lol { get; set; }
public void SetupPersistence(DbModelBuilder modelBuilder, string tenantSchema)
{
modelBuilder.Entity<Class2>().ToTable("Keke", tenantSchema);
modelBuilder.Entity<Class2>().HasKey(i => i.Id);
}
}
そして、これらをどのように使用するかを次に示します。
Database.SetInitializer<Context>(null);
Context.ProvisionTenant("personal");
Context.ProvisionTenant("work");
using (var db = Context.Create("personal"))
{
db.Set<Class2>().Add(new Class2 { Name = "Keke" });
db.SaveChanges();
foreach (var d in db.Set<Class2>())
{
Console.WriteLine(d.Name);
}
Console.Read();
}
CommonServiceLocatorを使用してMEF参照を保持しています。
さて、これにはいくつかの問題があります。
- プラグインはテーブル名を制御し、スキーマ名をテーブルに設定します-API側でこれをどのように制御するかわかりません。EF api全体を別のクラスにラップすることもできますが、1つの関数を希望どおりに機能させるだけでは、多くの問題が発生するようです。
- これのポイントは、プラグイン拡張可能なデータベースレイヤーを持つことであり、拡張性のポイントは、将来発生する変更に備えることです。現在、私の実装では、処理する方法がないため、変更部分が不十分です。プラグイン内の移行。
- それはひどいです。
移行を処理する方法、またはコンテキストからプラグインのテーブル名を明示的に定義する方法について、あらゆる入力を歓迎します。