本文章是由機器翻譯。

資料點

Entity Framework 6 中的 Code First 好處

Julie Lerman

下载代码示例

在我 2013 年 12 月的文章"Entity Framework6:忍者版"(msdn.microsoft.com/magazine/dn532202),描述了許多Entity Framework6 (EF6) 中的新功能。我不能深入到每一項功能,不過,所以這個月我就會鑽進的一些 EF6 增強特定的代碼第一次。兩個功能,我將討論的是有關的代碼第一個映射,以及其他涉及到的代碼第一次遷移。

一次載入 Fluent API 映射多

有兩種方法指定流利 (從您的類到您的資料庫) 模型的映射。一是直接在 OnModel­創建的 DbCoNtext 類,像這樣的方法:

modelBuilder.Entity<Casino>()
  .Property(c=>c.Name).IsRequired().HasMaxLength(200);
modelBuilder.Entity<PokerTable>()
  .Property(c => c.SerialNo).HasColumnName("SerialNumber");

當你有很多的映射時,您可以組織他們按類型到各自的 EntityTypeConfiguration 類,然後將添加到模型產生器使用這樣的代碼:

modelBuilder.Configurations.Add(new CasinoConfiguration());
modelBuilder.Configurations.Add(new PokerTableConfiguration());

然而,如果你有很多很多實體的映射,你可以結束與 OnModelCreating 中的很多重複性的 modelBuilder.Configurations.Add 方法。 若要消除此單調的工作,你可以現在所有 EntityTypeConfigurations 從都載入給定程式集使用單一方法。 在這裡我使用的新的 AddFromAssembly 方法來載入配置中運行的應用程式執行的程式集指定的:

modelBuilder.Configurations
  .AddFromAssembly(Assembly.GetExecutingAssembly())

此方法的一個不錯的功能是它並不它將載入的配置的範圍受限制。 甚至可以標記私人的自訂的 EntityTypeConfiguration 類和方法將會找到他們。 此外,AddFromAssembly 也理解中 EntityTypeConfigurations 的繼承層次結構。

AddFromAssembly 是一個島宇內利亞社區捐款數目。 請參閱利亞的博客帖子,"EF6:配置自動設置,"在 bit.ly/16OBuJ5 更多詳細資訊 — 你在那兒給他留了封感謝信。

定義您自己的預設架構

在我 2013 年 3 月資料點列中,"玩與 EF6 Alpha"(msdn.microsoft.com/magazine/jj991973),我談了一點有關架構支援的代碼第一次。 一項新功能是你可以在 OnModelCreating 中配置的映射:HasDefaultSchema。 這允許您指定的所有上下文映射到,而不是使用 dbo 的 EF 預設表的資料庫架構。 在"Entity Framework6:忍者版"文章,我執行了一些原始的 SQL 中關於 DbTransactions 的討論:

("Update Casino.Casinos set rating= " + (int) Casino.Rating)

你可能注意到我指定的 SQL 中的賭場架構。 我有一個名為賭場的架構的原因是因為我在我 DbCoNtext (CasinoSlotsModel) 的 OnModelCreating 方法中指定它:

modelBuilder.HasDefaultSchema("Casino");

我也談在 EF6 為反對在它具有不同架構的資料庫正在運行的代碼第一次遷移新的支援。 因為,自 EF6 阿爾法以來未變,我會讓你在我以前的專欄文章中讀到它。

要重建從任何點資料庫的遷移腳本

(和每一篇文章,只是重申規格) 規格中列出的代碼第一次遷移的新功能之一是""冪等的遷移腳本。現在,你可能是 comp sci 碩士學位人下你的皮帶,或者也許你是 DBA。 但我也不和我不得不抬頭的含義"冪等"。根據維琪百科,其中引用了 IBM 工程師 (bit.ly/9MIrRK):"在電腦科學中冪等一詞......來描述的操作,將產生相同的結果,如果一次或多次執行."我還可以查找如何發音。 它是眼-dem-愛倫 · 坡-帳篷。

在資料庫世界中,冪等可以用於描述時,總是有相同的影響,而不考慮其狀態資料庫的 SQL 腳本。 與代碼第一次遷移之前運行遷移,, 這樣的腳本將檢查看看是否那遷移已運行。 此功能是特定于-腳本參數的更新資料庫。

EF 總是提供了創建從某個特定的起始點 (源) 和 (可選) 到顯式的終結點 (目標) 通過所有遷移的步驟都運行的腳本的能力。 此 NuGet 命令喚起這種行為:

Update-Database -Script
  –SourceMigration:NameOfStartMigration
  –TargetMigration:NameOfEndMigrationThatIsntLatest

新的是生成的腳本是聰明多現在當您以特定方式調用該命令:

Update-Database -Script -SourceMigration $InitialDatabase

這也發生工作如果 0,用來替換 $InitialDatabase,雖然不能保證此替代方法將會支援在將來的版本。

回應,在腳本開頭的初始遷移和運載對最新的遷移。 這就是為什麼語法不顯式提供的源或目標遷移的名稱。

但與這一特定命令,EF6 將邏輯添加到檢查,看看哪些遷移已經執行的 SQL 特定遷移之前應用的腳本。 這裡是代碼的你會看到在腳本中的示例:

IF @CurrentMigration < '201310311821192_AddedSomeNewPropertyToCasino'
BEGIN
  ALTER TABLE [Casino].[Casinos] ADD [AgainSomeNewProperty] [nvarchar](4000)
  INSERT [Casino].[__MigrationHistory]([MigrationId], [ContextKey], [Model], [ProductVersion])
  VALUES (N'201310311821192_AddedSomeNewPropertyToCasino',
    N'CasinoModel.Migrations.Configuration', HugeBinaryValue , 
    N'6.1.0-alpha1-21011')
END

該代碼檢查­_MigrationHistory 表,看是否 AddedSomeNewPropertyToCasino 腳本已對資料庫尚未運行。如果它已從該遷移 SQL 將 exe­cuted。之前 EF6,腳本只是將運行 SQL 不進行檢查,是否它已運行已經看到。

提供程式的友好遷移歷史記錄表

EF6 允許您自訂的 _MigrationHistory 表如何定義使用一種功能稱為可自訂的遷移歷史記錄表。這是重要的如果您正在使用協力廠商資料提供程式都要求不同的預設值。圖 1 顯示的表的預設架構。

這裡是這怎樣能很有用的示例。關於 CodePlex,一個開發者注意到因為在兩個 Pk 中的每個 char 可以大於 1 個位元組、 他得到的複合鍵的長度從 MigrationId 中創建一個錯誤和 CoNtextKey 超出了允許的金鑰長度為 MySQL 表:767 位元組 (bit.ly/18rw1BX)。要解決這一問題,MySQL 團隊 HistoryCoNtext 內部使用的 EF6 版本的 MySQLADO.NET.net 的連接器上工作時改變兩個鍵列的長度 (bit.ly/7uYw2a)。

注意在圖 1 __MigrationHistory 表獲取我為使用 HasSchema 的上下文定義相同的架構:賭場。你可能具有說架構具有有限的許可權,應使用非資料的表,所以你可能想要更改的表的架構名稱的約定。你可以用 HistoryCoNtext,例如指定使用"admin"架構。


圖 1 預設的 __MigrationHistory 表的架構

HistoryCoNtext 源自 DbCoNtext,所以代碼應該是比較熟悉的如果你在過去與 DbCoNtext 和代碼第一次工作。圖 2 顯示了一個 HistoryCoNtext 類定義指定的管理架構。

圖 2 自訂 HistoryCoNtext 重新定義 __MigrationHistory 表

public class CustomHistoryContext : HistoryContext
{
  public CustomHistoryContext
   (DbConnection dbConnection, string defaultSchema)
     : base(dbConnection, defaultSchema)
  {
  }
  protected override void OnModelCreating(DbModelBuilder modelBuilder)
  {
    base.OnModelCreating(modelBuilder);
    modelBuilder.Entity<HistoryRow>()
      .ToTable("__MigrationHistory", "admin");
  }
}

您還可以使用像 Property() 的熟悉 API 呼叫。HasColumnType、 HasMaxLength 或 HasColumnName。 例如,如果您需要更改 CoNtextKey 的長度,你能做到:

modelBuilder.Entity<HistoryRow>()
  .Property(h => h.ContextKey).HasMaxLength(255);

如果你已經讀過最後一個月的 arti­cle,您應該熟悉 EF6 DbConfiguration。 這是您使用,讓您知道的關於 CustomHistory 的型號­上下文檔。 在您自訂 DbConfiguration 的建構函式,您需要指定要使用 HistoryCoNtext。 在這裡我設置為使用 CustomHistoryCoNtext 的SQL Server提供程式上下文:

SetHistoryContext(
  SqlProviderServices.ProviderInvariantName,
     (connection, defaultSchema) =>
  new CustomHistoryContext(connection,
     defaultSchema));

資料庫初始化和遷移功能將會看到此附加的上下文和相應地構造 SQL。中的表圖 3 創建使用自訂的 HistoryCoNtext 的 __MigrationHistory 表的架構名稱更改為管理員。(我不包括更改列長度的示例代碼)。


圖 3 自訂的 __MigrationHistory 表

HistoryCoNtext 是一個強大的功能,但它需要小心使用。但願您正在使用的資料庫提供程式將已經用它來指定目標資料庫,與相關的 __MigrationHistory 表,你甚至不需要想想這事兒。否則,我建議檢查有關此功能的 MSDN 文檔,並聽從其指導 (bit.ly/16eK2pD)。

創建自訂的遷移操作

如果您使用過遷移之前 — 不會自動但通過顯式創建並從封裝管理員主控台視窗中執行遷移 — 你可能已經探討了由添加遷移創建的遷移檔。如果是這樣,您可能會發現代碼第一次遷移有一個強型別的 API 來描述每個更改,使對資料庫架構:System.Data.Entity.Migrations.DbMigration。

圖 4 顯示了一個示例創建­表設置多個屬性的方法。

圖 4 DbMigrations.CreateTable 方法

CreateTable(
  Casino.SlotMachines",
  c => new
    {
      Id = c.Int(nullable: false, identity: true),
      SlotMachineType = c.Int(nullable: false),
      SerialNumber = c.String(maxLength: 4000),
      HotelId = c.Int(nullable: false),
      DateInService = c.DateTime(nullable: false),
      HasQuietMode = c.Boolean(nullable: false),
      LastMaintenance = c.DateTime(nullable: false),
      Casino_Id = c.Int(),
    })
  .PrimaryKey(t => t.Id)
  .ForeignKey("Casino.Casinos", t => t.Casino_Id)
  .Index(t => t.Casino_Id);

提供程式然後將翻譯成特定于資料庫 SQL 這些 API 呼叫。

有種方法創建表和索引,創建或修改的屬性,刪除物件和更多。這是一個相當豐富的 API,您可以看到從所列的可能性圖 5— 其中包括簡單地直接執行一些 SQL 的能力。但是,在某些情況下,它可能不足夠富裕,您的需要。例如,沒有創建資料庫檢視,指定許可權或許多其他操作的方法。


圖 5 DbMigrations 資料庫架構操作

再次,社會來解救。在 EF6,現在可以創建您可以通過自訂添加遷移所生成的遷移類調用的自訂遷移操作的能力。這是由於在 CodePlex 社區,Iñaki Elcoro,aka iceclow 另一個開發人員。

若要創建您自己的操作,必須執行幾個步驟。我會給每個步驟的核心。你可以看到完整的代碼和步驟如何組織的在這篇文章的下載。

  • 定義操作。在這裡我定義了 CreateView­操作,所列圖 6
  • 創建指向該操作的一種擴充方法。這使得簡單的從 DbMigration 調用:
public static void CreateView(this DbMigration migration,
  string viewName, string viewqueryString)
{
  ((IDbMigration) migration)
    .AddOperation(new CreateViewOperation(viewName,
       viewqueryString));
}
  • 定義的 SQL 操作中生成方法的一個自訂的 SqlServerMigrationSqlGenerator 類,如中所示圖 7
  • 告訴要使用自訂的 SqlServerMigrationSqlGenerator 類的 DbConfiguration 類:
SetMigrationSqlGenerator("System.Data.SqlClient",
  () => new CustomSqlServerMigrationSqlGenerator());

圖 6 自訂遷移操作創建資料庫檢視

public class CreateViewOperation : MigrationOperation
{
  public CreateViewOperation(string viewName, string viewQueryString)
    : base(null)
  {
    ViewName = viewName;
    ViewString = viewQueryString;
  }
  public string ViewName { get; private set; }
  public string ViewString { get; private set; }
  public override bool IsDestructiveChange
  {
    get { return false; }
  }
}

圖 7 自訂 SqlServerMigrationSqlGenerator 類

public class CustomSqlServerMigrationSqlGenerator
  : SqlServerMigrationSqlGenerator
{
  protected override void Generate(MigrationOperation migrationOperation)
  {
    var operation = migrationOperation as CreateViewOperation;
    if (operation != null)
    {
      using (IndentedTextWriter writer = Writer())
      {
        writer.WriteLine("CREATE VIEW {0} AS {1} ; ",
                          operation.ViewName,
                          operation.ViewString);
        Statement(writer);
      }
    }
  }
}

所有這一切在的地方,您現在可以使用新的操作中一個遷移檔和更新資料庫會知道用它做什麼。 圖 8 CreateView 操作顯示在使用中,並提供您還需要創建一個操作,以刪除該視圖,這將由下方法調用,如果你需要放鬆這種遷移的提醒。

圖 8 使用新的 CreateView 操作

public partial class AddView : DbMigration
  {
    public override void Up()
    {
      this.CreateView("dbo.CasinosWithOver100SlotMachines",
                      @"SELECT  *
                        FROM    Casino.Casinos
                        WHERE  Id IN  (SELECT   CasinoId AS Id
                        FROM     Casino.SlotMachines
                        GROUP BY CasinoId
                        HAVING COUNT(CasinoId)>=100)");
    }
    public override void Down()
    {
      this.RemoveView("dbo.CasinosWithOver100SlotMachines");
    }
  }

調用了更新資料庫之後,您可以看到在我的資料庫中的新視圖圖 9


圖 9 新創建的視圖生成由更新資料庫

代碼首先繼續進化

與代碼首先在地方的核心功能,微軟和開發人員從社會了開始一些波蘭人放 EF6,具有的功能,現在從更大的靈活性中獲益的機會。但它不會停止與 EF6 的發行。如果您篩選 CodePlex 工作項的版本超出 6.0.1 版 (在 bit.ly/1dA0LZf),您可以看到更多波蘭人被添加到 EF6 和代碼第一次的未來版本。這些專案是在不同的國家。你或許會找到一個你想工作。

Julie Lerman* 是 Microsoft MVP、.NET 导师和顾问,住在佛蒙特州的山区。您可以在全球的用户组和会议中看到她对数据访问和其他 Microsoft .NET 主题的演示。在她博客thedatafarm.com/blog 和的作者是"程式設計Entity Framework"(2010 年) 以及代碼第一版 (2011 年) 和 DbCoNtext 版 (2012 年),所有從 O'Reilly 媒體。跟著她在 Twitter 上 twitter.com/julielerman 看看她的 Pluralsight 課程 juliel.me/PS-視頻。*

感謝以下協助校閱本篇文章的技術專家:榮恩Miller(Microsoft)