3

我一直都是面向數據庫的程序員,所以直到今天,我一直使用數據庫驅動的編程方法,我對T- SQL和SQL Server。試用EF代碼優先和遷移 - 絆腳石

我想換我的頭周圍的實體框架6 代碼優先方法 - 坦率地說 - 我掙扎。

我有一個現有的數據庫 - 所以我做了Add New Item > ADO.NET Entity Data Model > Code-First from Database,我得到了一堆代表我現有數據庫的C#類。到現在爲止還挺好。

我現在要做的是探索如何處理正在進行的數據庫升級 - 無論是架構還是「靜態」(預填充)查找數據。我的第一個抱怨是,從數據庫反向工程的實體正在使用Fluent API進行配置,而創建我想創建爲具有數據註釋的C#類的新表似乎更自然。 「混合」這兩種方法有什麼問題嗎?或者我可以告訴逆向工程步驟只使用數據註釋屬性而不是Fluent API?我試圖創建漂亮的和小的遷移 - 每個要添加的每一組功能(例如,新表,新索引,一些新列等等) ) - 但看起來我不能有超過一個「待定」遷移......當我有一個,並且我進一步修改我的模型類,並且我嘗試使用add-migration (name of migration)進行第二次遷移,我是與:

無法生成顯式遷移,因爲以下顯式遷移未決:[201510061539107_CreateTableMdsForecast]。在嘗試生成新的顯式遷移之前應用待處理的顯式遷移。

認真?!?!?我不能有超過一個,單個等待移植?我需要在每次微小遷移後運行update-database我正在添加?

好像是一個BIG缺點!我寧願創建我的10,20個小巧,易於理解的遷移,然後然後將它們一舉全部應用 - 無法做到這一點!?!?這真的很難相信.....任何方式呢?

+0

關於你的第一個問題,你可能能夠自定義使用的T4模板(https://www.nuget.org/packages/EntityFramework.CodeTemplates.CSharp/),但這是很多工作。我已經越來越意識到我可以如何將我的擔憂與流利的API分開,我創建了一個映射文件夾並在那裏完成所有配置。 –

+0

對於遷移,我建議您使用小增量包。然後,當我準備進行生產部署時,我將使用-Source和-Target屬性重新開發我的開發數據庫,​​然後在生成我們的DBA需要的單個腳本之前全部重新應用它們。 –

回答

5

確實,在開發期間,您只能在時間內打開一個待定遷移。爲了理解爲什麼,您必須瞭解遷移是如何生成的。生成器通過比較數據庫的當前狀態(模式)和模型代碼的當前狀態來工作。然後它有效地創建一個「腳本」(一個C#類),它改變數據庫的模式以匹配模型。你不想同時有多個這樣的待處理的文件,否則這些文件會相互衝突。讓我們舉個簡單的例子:

比方說,我有一個類Widget:在數據庫

class Widget 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 
} 

和匹配表Widgets

Widgets 
------- 
Id (int, PK, not null) 
Name (nvarchar(100), not null) 

現在我決定要添加新的屬性Size我的班級。

class Widget 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 
    public int Size { get; set; } // added 
} 

當我創建我的遷移,發電機看着我的模型,它與數據庫進行比較,並認爲我的Widget模型現在有一個Size特性而相應的表沒有一個Size列。因此,所產生的遷移最終看起來像這樣:

public partial class AddSizeToWidget : DbMigration 
{ 
    public override void Up() 
    { 
     AddColumn("dbo.Widgets", "Size", c => c.Int()); 
    } 

    public override void Down() 
    { 
     DropColumn("dbo.Widgets", "Size"); 
    } 
} 

現在,想象它允許創建第二個遷移,同時第一仍懸而未決。我還沒有運行Update-Database命令,所以我的基準數據庫模式仍然是相同的。現在我決定添加另一個屬性ColorWidget

當我爲此更改創建遷移時,生成器會將我的模型與數據庫的當前狀態進行比較,並看到我已添加兩列列。因此,創建相應的腳本:

public partial class AddColorToWidget : DbMigration 
{ 
    public override void Up() 
    { 
     AddColumn("dbo.Widgets", "Size", c => c.Int()); 
     AddColumn("dbo.Widgets", "Color", c => c.Int()); 
    } 
    ... 
} 

所以現在我有兩個懸而未決的遷移,且二者都去嘗試一個Size列添加到數據庫中,當他們最終運行。顯然,這是行不通的。所以這就是爲什麼一次只允許一個未決遷移被打開的原因。

因此,在開發過程中的一般工作流程是:

  1. 更改模型
  2. 生成遷移
  3. 更新的數據庫來建立一個新的基線
  4. 重複

如果您犯了一個錯誤,您可以使用–TargetMigration參數將數據庫回滾到以前的遷移的Update-Database命令,然後從您的項目中刪除錯誤的遷移並生成一個新的遷移。 (如果你真的想要,你可以用這種方法將幾個小的遷移組合成一個更大的塊,儘管我發現在實踐中這是不值得的)。

Update-Database –TargetMigration PreviousMigrationName 

現在,當需要更新生產數據庫時,您不必一次手動應用每個遷移。這就是遷移的美妙之處 - 只要您針對數據庫運行更新的代碼,就會自動應用它們。在初始化期間,EF查看目標數據庫並檢查遷移級別(這存儲在啓用數據庫遷移時創建的特殊__MigrationHistory表中)。對於尚未應用的代碼中的任何遷移,它將全部運行它們,以便使數據庫保持最新狀態。

希望這有助於澄清事情。

1

有沒有用「混合」這兩個方法的任何問題/問題?

  1. 不,混合它們沒有問題。
  2. 您可以使用流暢的配置比使用數據註釋做得更多。構建遷移腳本時
  3. 流利的配置覆蓋數據註解。
  4. 您可以使用數據標註動態生成的DTO和前端/ UI約束 - 節省了大量的代碼。
  5. 流利的API有類EntityTypeConfiguration,它允許你創建一個對象域(DDD中的意義上的)動態,並將其儲存 - 用的DbContext加快工作了很多。

我不能有比一個單一的 「未決」 遷移

  1. 不是100%真更多。 (也許50%,但是這不是一個攪局者)
  2. 是的,DbMigrator模型「哈希」比較數據庫模型「哈希」,當它生成數據庫 - 因此它的塊時,你讓你的新的小型遷移之前。但這不是認爲你不能進行小型遷移步驟的理由。我一直只做很小的遷移步驟。
  3. 當你開發一個應用程序,你用你的本地數據庫您可以通過一個應用小遷移一個爲您開發功能 - 逐步顯現。最後,您將部署所有新的功能,將所有小型遷移集成到一個dll中,然後逐個應用它們。