本文章是由機器翻譯。

資料點

EF6 代碼第一次遷移多個模型

Julie Lerman

下載代碼示例

Julie LermanEntity Framework6 介紹的支援代碼第一次遷移,以更好地處理將多個模型的資料存儲在一個單一的資料為­基地。但支援是非常特定的並且可能不是你的想像。在本文中,您將瞭解此功能,無論做什麼和不做的與看到如何使用它。

完全不同的模型,不同的表,不同的資料:相同的資料庫

EF6 遷移支援遷移是彼此完全獨立的多個模型。這兩個實現此功能 — — 使用鍵來標識一組遷移或者使用組遷移歷史資料庫架構與表的單個模型 — — 允許您在同一資料庫中存儲獨立、 獨特的模式。

不是共用資料模型之間或多租戶資料庫

它是容易使人誤解的這種功能,好處,所以我想馬上明確在什麼上不受支援。

這種新的多模型支援不被為了複製單個模型和跨多個架構有多租戶資料庫。

我們許多人希望,當我們看到此功能的其他模式是跨多個模型共用一個共同的實體 (和它的資料) 和將實體映射到單個資料庫的能力。這是一種非常不同的問題,不過,並不是那種容易解決了Entity Framework。我曾經嘗試,但放棄了。我在本專欄中的資料庫之間共用資料寫以前的文章 (請參閱"跨域驅動設計包括上下文的共用資料模式第 2 部分"在 bit.ly/1817XNT)。我還提出了一個會話在 TechEd 歐洲被稱為"在領域驅動設計包括上下文中的Entity Framework模型分區",其中錄得和可在 bit.ly/1AI6xPa

模式一:CoNtextKey 是關鍵

一種新的工具 EF6 提供要啟用此功能是 CoNtextKey。這是資料庫的一個新的領域,在 MigrationHistory 表中跟蹤的每個遷移。它結成新的 DbMigrations 中具有相同名稱的屬性­配置 < TCoNtext > 類。

預設情況下,CoNtextKey 將繼承與該上下文相關聯的 DbMigrationsConfiguration 的強型別的名稱。作為一個例子,這裡是一個 DbCoNtext 類,適用于醫生和集類型:

namespace ModelOne.Context
{
  public class ModelOneContext:DbContext
  {
    public DbSet<Doctor> Doctors { get; set; }
    public DbSet<Episode> Episodes { get; set; }
  }
}

一如往常,啟用遷移命令的預設行為是創建一個具有名稱 [YourNamespace] 的 DbMigrationsConfiguration 類。Migrations.Configuration。

當我申請特定的遷移 (那就是,當調用更新-­Visual Studio封裝管理員主控台中的資料庫),Entity Framework不會只應用遷移,它也會向 __MigrationHistory 表中添加一個新行。這裡是該操作的 SQL:

INSERT [dbo].[__MigrationHistory]([MigrationId], [ContextKey], [Model],
  [ProductVersion])
VALUES (N'201501131737236_InitialModelOne',
  N'ModelOne.Context.Migrations.Configuration',
  [hash of the model], N'6.1.2-31219')

請注意進入 CoNtextKey 欄位的值是模型­One.CoNtext.Migrations.Configuration,這是我的 DbMigrationsConfiguration < TContext > 的強型別的名稱 類。

您可以通過指定上下文控制 CoNtextKey 名稱­鍵的類建構函式中的 DbMigrationsConfiguration 類的屬性。我會將它重命名為 ModelOne:

public Configuration()
{
  AutomaticMigrationsEnabled = false;
  ContextKey = "ModelOne";
}

現在執行遷移,將使用 ModelOne 的 CoNtextKey 欄位的遷移表。然而,如果你已經已經執行遷移與預設值,這不會很好。EF 將嘗試重新應用所有的遷移過程,其中包括創建的表及其他資料庫物件,從而導致資料庫拋出錯誤,因為重複的物件。所以我的建議是更改該值應用任何遷移前的,否則您將必須手動更新 __MigrationsHistory 表中的資料。

我已經確定我 DbCoNtext 型點為連接字串我已經命名為 MultipleModelDb。而不是依賴于代碼第一次公約 》,以查找具有相同的名稱上下文的連接字串,我想要一個連接字串可以針對此資料庫的任何模型。這通過指定上下文建構函式繼承 DbCoNtext 重載,它需要連接字串的名稱?這裡是 ModelOneCoNtext 的建構函式:

public ModelOneContext()
       : base("MultipleModelDb") {
}

添加遷移和更新資料庫將能夠找到連接字串中,所以我確信遷移正確的資料庫。

兩種情況下,兩個 CoNtextKeys

現在,你看到 CoNtextKey 的作品,讓我們添加在另一個與它自己的 CoNtextKey 模型。我把此模式在一個單獨的專案。這樣做,當你在同一個專案有多個模型的模式是稍有不同 ; 在這篇文章中,我將演示,進一步沿。這是我新的模型,ModelTwo:

namespace ModelTwo.Context
{
  public class ModelTwoContext:DbContext
  {
    public DbSet<BBCEmployee> BbcEmployees { get; set; }
    public DbSet<HiringHistory> HiringHistories { get; set; }
  }
}

ModelTwoCoNtext 適用于完全不同的域類。下面是它的 DbConfiguration 類,我指定的 CoNtextKey 被稱為 ModelTwo 的位置:

internal sealed class Configuration : DbMigrationsConfiguration<ModelTwoContext>
  {
    public Configuration()
    {
      AutomaticMigrationsEnabled = false;
      ContextKey = "ModelTwo";
    }

當調用更新資料庫對包含 ModelTwoCoNtext 的專案時,在同一資料庫中創建新的表和一個新行添加到 __MigrationHistory 表。這一次的 CoNtextKey 值是 ModelTwo,正如你看到的由遷移的 SQL 程式碼片段中:

INSERT [dbo].[__MigrationHistory]([MigrationId], [ContextKey], [Model], [ProductVersion])
VALUES (N'201501132001186_InitialModelTwo', N'ModelTwo', [hash of the model], N'6.1.2-31219')

我隨著我的功能變數名稱,我的 DbCoNtext 和我的資料庫,EF 遷移將總是檢查返回到使用適當的 CoNtextKey 的 __MigrationHistory 表中執行遷移的相關集。這樣它將能夠確定要考慮到模型的更改的資料庫的更改。這將允許 EF 要正確處理存儲在資料庫中的多個 DbCoNtext 模型遷移。但請記住,它是唯一能夠工作,因為在這兩個模型映射到其中的資料庫表沒有重疊。

模式二:資料庫架構分離模型和遷移

您可以使用來允許遷移,以處理單個資料庫中的多個模型的其他模式是分開的遷移和相關表與資料庫架構。這是因為接近,你可以得到,只針對單獨的資料庫,沒有一些開銷 (例如維護和費用) 資源您可能招致多個資料庫。

EF6 使得它更容易通過配置它與一個新的 DbModelBuilder.HasSchema 映射定義為一種單一模式的資料庫架構。這將重寫預設架構名稱,其中,對於SQL Server,是 dbo。

請記住即使您不指定上下文鍵,將使用預設名稱。那麼還有沒有點中刪除上下文關鍵屬性我集以說明 HasSchema 屬性如何影響遷移。

架構會為每個我在 OnModelCreating 方法中的兩個上下文類了。這裡是 ModelTwoCoNtext,我已經指定為具有名為 ModelTwo 的架構的相關代碼:

protected override void OnModelCreating(DbModelBuilder modelBuilder) {
    modelBuilder.HasDefaultSchema("ModelTwo");
  }

其他上下文將獲取架構名稱 ModelOne。

其結果是該資料庫的所有物件的模型­TwoCoNtext 地圖將在 ModelTwo 架構。此外,EF 將在 ModelTwo 架構中提出這種模型的 __MigrationHistory 表。

來演示這乾淨的方式,我指向不同的資料庫,比前面的示例中,應用所有的遷移。請記住,設置的 HasDefaultSchema 方法是變更映射,需要添加新的遷移,將其應用到資料庫的更改。圖 1 他們單獨的架構中顯示的遷移和資料的表。

遷移和表分為資料庫架構
圖 1 遷移和表分為資料庫架構

展望將來,只要您與任一種情況下,遷移進行交互,因為他們降級到他們個人的架構,EF 不會有單獨維護它們的問題。作為提醒,要注意關鍵的模式在這裡,這就是映射到這兩個模型的表沒有重疊。

單個專案中的多個模型

你目前為止看到的兩個例子 — — 使用 CoNtextKey 或資料庫架構來分隔模型遷移 — — 設定了與封裝在它自己的專案中的每個模型。這是我喜歡的我的解決方案的構建方式。但這也是可能的和在許多情況下,完全合理的在同一個專案中有您的模型。無論您使用 CoNtextKey 或資料庫架構保持遷移整理出來,你可以達到這個加 NuGet 命令只有幾個額外參數。

這些例子清楚地分開,我會用相同的類來創建新的解決方案。我會記住的域類的單獨的專案,但這兩種模型在同一專案中,如中所示圖 2

將多個 DbCoNtext 類放在一個單一的專案
圖 2 將多個 DbCoNtext 類放在一個單一的專案

如你所知,預設情況下,啟用-­遷移將創建一個名為您的解決方案中發現 DbCoNtext 為遷移資料夾。如果您有多個 DbCoNtexts,像現在,啟用遷移不會隨便選擇 DbCoNtext 創建遷移 ; 相反,它將返回指示您使用 CoNtextTypeName 參數來指示哪個 DbCoNtext 使用的非常有用資訊。該消息是真好你可以只是複製和粘貼從要運行必要的命令的消息。這裡是我的專案返回的消息:

PM> enable-migrations
More than one context type was found in the assembly 'ModelOne.Context'.
To enable migrations for 'ModelOne.Context.ModelOneContext', use
 Enable-Migrations -ContextTypeName ModelOne.Context.ModelOneContext.
To enable migrations for 'ModelTwo.Context.ModelTwoContext', use
 Enable-Migrations -ContextTypeName ModelTwo.Context.ModelTwoContext.

除了 — — CoNtextTypeName 參數,我將添加在 MigrationsDirctory 參數顯式命名此資料夾,使它更方便我來管理專案資產:

Enable-Migrations
-ContextTypeName ModelOne.Context.ModelOneContext
-MigrationsDirectory ModelOneMigrations

圖 3 顯示新資料夾與創建每個遷移其配置類。

結果時啟用遷移指定的 DbCoNtext 和目錄名稱Migrations
圖 3 結果時啟用遷移指定的 DbCoNtext 和目錄名稱

運行啟用遷移也將代碼添加到 DbConfiguration 的類,這使他們意識到的目錄名稱。這裡是 ModelOneCoNtext 的配置類為例 (ModelTwoCoNtext 的 DbConfiguraton 檔將設置其目錄名稱為 ModelTwoMigrations,作為指定):

internal sealed class Configuration : DbMigrationsConfiguration<ModelOne.Context.ModelOneContext>
  {
    public Configuration()
    {
      AutomaticMigrationsEnabled = false;
      MigrationsDirectory = @"ModelOneMigrations";
    }

因為我現在有兩個類命名配置,我會被迫完全限定他們任何需要的時候使用它們。所以我會將第重命名為 ModelOneDbConfig (如下面的代碼中所示) 和第二個為 ModelTwoDbConfig:

internal sealed class ModelOneDbConfig : DbMigrationsConfiguration<ModelOneContext>
  {
    public ModelOneDbConfig()
      {
        AutomaticMigrationsEnabled = false;
        MigrationsDirectory = @"ModelOneMigrations";
      }
  }

您還可以指定 CoNtextKey,如果您想要重寫預設值,但這樣獨自一人吧。請記住我並未指定 HasDefaultSchema 映射方法在 DbCoNtext 班這樣的遷移歷史記錄表和其它資料庫物件將被安置在自己的架構。

現在正是時候添加這兩種模型的遷移,並將它們應用到我的資料庫。再次,我要直接向哪個模型和遷移到使用 EF。通過指向遷移設定檔,EF 會知道要使用哪個模型和在哪一個目錄來存儲遷移檔。

這裡是我的命令,用於添加遷移為 CoNtextOne (請記住我改變了配置類名稱,所以我不需要使用其完全限定的名為 ConfigurationTypeName):

add-migration Initial
  -ConfigurationTypeName ModelOneDbConfig

由此產生的遷移檔獲取創建在 ModelOne­遷移目錄。就為 ModelTwo 這樣做了之後,我也有一個遷移檔 ModelTwoMigrations 目錄中。

現在正是時候要應用這些遷移。我需要再指定 ConfigurationTypeName,以便 EF 知道要使用哪些遷移。這裡是 ModelOne 的命令:

update-database
  -ConfigurationTypeName ModelOneDbConfig

會為 ModelTwo 跑,和相關的命令:

update-database
  -ConfigurationTypeName ModelTwoDbConfig

在運行這些命令之後, 我的資料庫看上去一樣一樣圖 1

我修改我的模特和添加並應用遷移,我只需要記住要指定正確配置類中的每個命令的參數。

非常適合與域驅動設計建模

在最近的兩個部分資料點專欄叫做"A 模式為共用資料跨領域驅動設計界語境",我寫了關於跨域的持久化,單獨的資料庫共用資料。第一部分是在 bit.ly/1wolxz2 和第二部分是在 bit.ly/1817XNT。很多開發商已經指出維護一個單獨的資料庫部署可以是一種負擔和付費在雲中託管的單獨資料庫可以是昂貴。你在這篇文章申辦表學到的技術和多個模型在一個單一的資料庫中的資料可以説明您類比完整的資料庫分離。EF6 遷移中這個新的支援為那些開發人員提供了一個很好的解決方案。


Julie Lerman 是 Microsoft MVP,.NET 的導師和顧問,住在佛蒙特州的山。你可以找到她提出關於資料訪問和 other.NET 的主題,在使用者組和世界各地的會議。她的博客 thedatafarm.com/blog ,是作者的"程式設計Entity Framework"(2010 年),以及代碼第一版 (2011 年) 和 DbCoNtext 版 (2012 年),所有從 O'Reilly 媒體。跟著她在 Twitter 上 twitter.com/julielerman ,看看她的 Pluralsight 課程 juliel.me PS 的-視頻

感謝以下的微軟技術專家對本文的審閱:羅文Miller