我已經啓動了一個EF6項目來存儲分析儀器的測量結果。每臺儀器都有一個內置的PC和它自己的結果數據庫。Entity Framework 6代碼優先遷移 - 從CreateDatabaseIfNotExists初始化程序開始
最初,使用了數據庫初始化程序CreateDatabaseIfNotExists。創建數據庫時,它會在__MigrationHistory表中創建一個條目,其中包含一個非唯一的MigrationId條目(時間戳因儀器而異,例如201706011336597_InitialCreate),ContextKey(如果我的派生DbContext的完全限定類型)。
過了一段時間,決定將更多的結果數據添加到數據庫中......幸運的是,只需要三個新表格。現有表格中沒有更改。
爲此,我想使用MigrateDatabaseToLatestVersion初始值設定項。但我必須支持以下兩種情況:
- 具有非唯一MigrationId的現有數據庫必須使用三個新表遷移到擴展版本。
- 沒有數據庫,用MigrateDatabaseToLatestVersion初始化器創建數據庫。
我該怎麼做?
我已經使用初始DbContext中的add-migration PM控制檯命令創建了初始遷移。這與方案2(沒有數據庫存在)很相稱。從這個起點,我可以更新我的DbContext並使用三個新表創建一個新的遷移。
但是如何支持場景1?初始遷移的Up()方法包含表創建代碼,這不是必要的,因爲這些表已經存在。是一個空的遷移(add-migration -IgnoreChanges)有幫助,也許有比初始遷移更晚的時間戳?
注意:我無法從PM控制檯訪問目標數據庫,只能在我的開發人員計算機上訪問測試數據庫。
感謝和問候
卡斯滕
更新: 我已經修改了創建初始遷移與靜態標誌TablesAlreadyCreated。
public partial class InitialMigraCreate : DbMigration
{
/// <summary>
/// Set this field to true, if the tables are already created by the
/// CreateDatabaseIfNotExists database initializer. Then, the Up()
/// and Down() methods do nothing, but the
/// migration is added to the __MigrationHistory table.
/// </summary>
public static bool TablesAlreadyCreated = false;
public override void Up()
{
if (TablesAlreadyCreated)
return;
// several CreateTable calls here
}
/// <inheritdoc/>
public override void Down()
{
if (TablesAlreadyCreated)
return;
// several Drop... calls here
}
}
我還實施了一個新的數據庫初始化類,如下所示:
public class MigrateDatabaseToLatestVersionEx<TContext, TMigrationsConfiguration> : IDatabaseInitializer<TContext>
where TContext : DbContext
where TMigrationsConfiguration : DbMigrationsConfiguration<TContext>, new()
{
...
/// <inheritdoc />
public virtual void InitializeDatabase(TContext context)
{
if (context == null)
throw new ArgumentNullException("context");
// check whether a first migration exists from the CreateDatabaseIfNotExists database initializer
var firstConfig = new ConfigurationAutoCreatedDatabase();
firstConfig.TargetDatabase = _config.TargetDatabase;
var firstMigrator = new DbMigrator(firstConfig);
var firstDbMigrations = firstMigrator.GetDatabaseMigrations();
// create the default migrator with the current configuration
var migrator = new DbMigrator(_config);
if (1 == firstDbMigrations.Count(migra => migra.EndsWith("_InitialCreate", StringComparison.InvariantCultureIgnoreCase)))
{ // This database was created using the CreateDatabaseIfNotExists database initializer.
// That's an indication whether it's an old database
// Do the custom migration here!
InitialMigraCreate.TablesAlreadyCreated = true;
migrator.Update();
}
else
{ // do the default migration the database was created with this MigrateDatabaseToLatestVersionEx initializer
InitialMigraCreate.TablesAlreadyCreated = false;
migrator.Update();
}
}
}
它檢查,初始遷移條目是從CreateDatabaseIfNotExists初始化和禁用表創建/刪除通話在這種情況下,Up()/ Down()方法。 ConfigurationAutoCreatedDatabase是手動創建的派生類DbMigrationsConfiguration:
internal sealed class ConfigurationAutoCreatedDatabase : DbMigrationsConfiguration<MyNamespace.MyDbContext>
{
/// <summary>
/// Creates a <c>ConfigurationAutoCreated</c> object (default constructor).
/// </summary>
public ConfigurationAutoCreatedDatabase()
{
this.AutomaticMigrationsEnabled = false;
this.AutomaticMigrationDataLossAllowed = false;
this.ContextKey = "MyNamespace.MyDbContext";
}
}
所以,它適用於這兩種方案。我希望能幫助其他有類似問題的人。有趣的是,如果該任務有一個開箱即用的EF工作流程。
感謝您的回覆。我再次測試了工作流程,發現在使用PM控制檯命令** Enable-Migrations **啓用遷移時指定** - ContextTypeName **參數非常重要。結果,生成的Configuration類的'ContextKey'屬性用我們派生的'DbContext'的完全限定名初始化。否則,生成的「Configuration」類的'ContextKey'屬性將使用生成的'Configuration'類本身的全限定名進行初始化。然後,遷移不起作用。 – KBO
解決方法之一是在構造函數中明確地給出一個contextkey。見[這裏](https://msdn.microsoft.com/en-us/magazine/dn948104.aspx) –
你是對的,解釋(見給出的鏈接)澄清。我最後使用的** - ContextTypeName **參數具有類似的結果,即'DbMigrationsConfiguration'中的右邊的'ContextKey'屬性。問題是,'MigrateDatabaseToLatestVersion'類的默認行爲不適用於以前使用的'CreateDatabaseIfNotExists'類。現在它工作...謝謝 – KBO