[英]EF code first: inherited dbcontext creates two databases
我正在嘗試創建一個基本dbcontext,其中包含所有常用實體,這些實體將始終在多個項目中重用,如頁面,用戶,角色,導航等。
這樣做我有一個ContextBase類繼承DbContext並定義我想要的所有DbSet。 然后我有一個Context類繼承ContextBase,我定義項目特定的DbSet。 這些類定義如下:
public class ContextBase : DbContext
{
public virtual DbSet<User> Users { get; set; }
//more sets
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new UsersConfiguration());
//add more configurations
}
}
public class Context : ContextBase
{
public DbSet<Building> Buildings { get; set; }
//some more project specific sets
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Configurations.Add(new BuildingsConfiguration());
//add more project specific configs
}
}
在我的global.asax中:
Database.SetInitializer(new MigrateDatabaseToLatestVersion<Context, Configuration>());
其中Configuration引用繼承DbMigrationsConfiguration並重寫Seed方法的類。
兩個上下文類在同一名稱空間中定義,但是交叉程序集(為了我可以在多個現有項目中更新基礎項目而不觸及項目特定代碼) - 不確定這是否相關。
我的問題:運行此代碼時,它工作正常,但在查看數據庫時,它實際上創建了兩個不同的數據庫! 一個包含所有基本實體表,另一個包含BOTH基表和自定義表。 CRUD操作只在自定義版本上執行(這顯然是我想要的),但為什么它也會創建另一個版本的模式?
任何幫助表示贊賞,謝謝!
更新:
以下代碼是我最終得到的。 它並不理想,但它確實有效。 我仍然希望獲得有關如何改進這一點的反饋,但與此同時,我希望這有助於推動這一進程。 我真的不推薦這樣做! 它非常容易出錯並且非常令人沮喪。 我只是發布這個,看看是否有更好的想法或實現來實現這一目標。
仍然存在的一個(但不是唯一的)問題是必須手動將MVC視圖添加到項目中。 我已經將它添加到Nuget包中,但是當VS連接到TFS時,需要2到3個小時來應用具有如此多文件的nuget包。 通過一些更多工作和自定義View引擎,可以預編譯視圖( http://blog.davidebbo.com/2011/06/precompile-your-mvc-views-using.html )。
該解決方案分為Base Framework項目和Custom項目(每個類別包括自己的模型和存儲庫模式)。 框架項目打包在Nuget包中,然后安裝在任何自定義項目中,允許任何項目的常用功能,如用戶,角色和權限管理,內容管理等(通常稱為Boiler Plate)輕松添加到任何新項目。 這允許在任何現有的自定義項目中遷移樣板的任何改進。
定制數據庫初始化器:
public class MyMigrateDatabaseToLatestVersion : IDatabaseInitializer<Context>
{
public void InitializeDatabase(Context context)
{
//create the base migrator
var baseConfig = new FrameworkConfiguration();
var migratorBase = new DbMigrator(baseConfig);
//create the custom migrator
var customConfig = new Configuration();
var migratorCustom = new DbMigrator(customConfig);
//now I need to check what migrations have not yet been applied
//and then run them in the correct order
if (migratorBase.GetPendingMigrations().Count() > 0)
{
try
{
migratorBase.Update();
}
catch (System.Data.Entity.Migrations.Infrastructure.AutomaticMigrationsDisabledException)
{
//if an error occured, the seed would not have run, so we run it again.
baseConfig.RunSeed(context);
}
}
if (migratorCustom.GetPendingMigrations().Count() > 0)
{
try
{
migratorCustom.Update();
}
catch (System.Data.Entity.Migrations.Infrastructure.AutomaticMigrationsDisabledException)
{
//if an error occured, the seed would not have run, so we run it again.
customConfig.RunSeed(context);
}
}
}
}
Framework的數據庫遷移配置:
public class FrameworkConfiguration: DbMigrationsConfiguration<Repository.ContextBase>
{
public Configuration()
{
AutomaticMigrationsEnabled = false;
}
public void RunSeed(Repository.ContextBase context)
{
Seed(context);
}
protected override void Seed(Repository.ContextBase context)
{
// This method will be called at every app start so it should use the AddOrUpdate method rather than just Add.
FrameworkDatabaseSeed.Seed(context);
}
}
Custom Project的數據庫遷移配置:
public class Configuration : DbMigrationsConfiguration<Repository.Context>
{
public Configuration()
{
AutomaticMigrationsEnabled = false;
}
public void RunSeed(Repository.Context context)
{
Seed(context);
}
protected override void Seed(Repository.Context context)
{
// This method will be called at every app start so it should use the AddOrUpdate method rather than just Add.
CustomDatabaseSeed.Seed(context);
}
}
自定義DbContext
//nothing special here, simply inherit ContextBase, IContext interface is purely for DI
public class Context : ContextBase, IContext
{
//Add the custom DBsets, i.e.
public DbSet<Chart> Charts { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
//Assign the model configs, i.e.
modelBuilder.Configurations.Add(new ChartConfiguration());
}
}
框架DbContext:
//again nothing special
public class ContextBase: DbContext
{
//example DbSet's
public virtual DbSet<Models.User> Users { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder);
}
在global.asax AppStart中:
//first remove the base context initialiser
Database.SetInitializer<ContextBase>(null);
//set the inherited context initializer
Database.SetInitializer(new MyMigrateDatabaseToLatestVersion());
在web.config中:
<connectionStrings>
<!--put the exact same connection string twice here and name it the same as the base and overridden context. That way they point to the same database. -->
<add name="Context" connectionString="Data Source=.\SQLEXPRESS; Initial Catalog=CMS2013; Integrated Security=SSPI;MultipleActiveResultSets=true;" providerName="System.Data.SqlClient"/>
<add name="ContextBase" connectionString="Data Source=.\SQLEXPRESS; Initial Catalog=CMS2013; Integrated Security=SSPI;MultipleActiveResultSets=true;" providerName="System.Data.SqlClient"/>
</connectionStrings>
(來自評論)
您正在直接創建ContextBase
對象,顯然是在使用ContextBase
作為泛型類型參數的泛型方法中的new T()
,因此ContextBase
任何初始化程序也會運行。 要防止創建ContextBase
對象(如果永遠不應該直接實例化,如果應始終使用派生的上下文),則可以將該類標記為abstract
。
你的ContextBase
似乎也有一個初始化器。你可以刪除它
Database.SetInitializer<ContextBase>(null);
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.