2016 年 11 月

第 31 卷,第 11 期

本文章是由機器翻譯。

技術最前線 - Code First 與資料庫初始化

Dino Esposito | 2016 年 11 月

Dino Esposito「 DevOps 」 一詞是相對而言比較新,而且最近有增加,以包含更多活動,最值得注意的是自動化的測試和部署 — 我相信自動化的開發人員作業的第一個範例是以舊軟體本身。我指建立並初始化資料庫應用程式安裝期間的特定功能。許多軟體公司開發垂直然後賣給各種不同的客戶並調整其需求的系統。

可自訂的部分取決於產品和商務網域的特性,但是我敢說起碼任何垂直軟體應用程式,需要有特定客戶的資料庫。因此,資料庫必須建立的資料表和結構描述所需的內容,並填入臨機操作的資料。

可永遠自動化並內建在產品本身並不是所有的必要的工作。例如,假設匯入現有的資料。是否要匯入資料位於 Excel 檔案或舊版的資料庫中,很可能以某種方式來處理資料,並將其載入至新的存放裝置,必須建立匯入工具。不過,如果您使用 Entity Framework 6.x 中的 Code First 資料存取層的應用程式,然後至少建立資料庫結構描述,而且資料表可輕易自動化並以透明的方式可能會發生第一次執行應用程式。

在本專欄中,我將摘要說明從多客戶應用程式的觀點來看早期以來已在 Code First 提供一些功能。特別是,我將著重在如何建立和填入資料庫,以及如何以程式設計方式定義其名稱和連接字串。 

配置是全新的資料表結構描述

讓我們假設您有全新的 Visual Studio 專案已連結至 Entity Framework 6.x NuGet 封裝。您可能要採取的下一個步驟是建立資料存取類別庫,或至少是不同的資料夾中目前的專案以某種方式來儲存所有檔案 concur 與資料存取功能的工作。根據 Entity Framework 的規則,您需要有代表應用程式的資料管理子系統中的進入點的 DbContext 類別。這類應用程式特定類別的範例如下︰

public class RegionsContext : DbContext
{
  ...
}

以應用程式的眼睛 DbContext 衍生類別的小於否,資料庫。預期類別會公開少數幾個 DbSet < T > 的屬性,一個用於每個受管理的應用程式之實體的集合。< T > DbSet 屬性是邏輯上等同於實體資料庫中的資料表︰

public class RegionsContext : DbContext
{
  public DbSet<Region> Regions { get; set; }
}

程式碼片段的結果是讓應用程式使用關聯式資料庫時,其中包含名為區域的資料表。資料表的結構描述呢? 區域類別的公用的配置取決於結構描述。程式碼第一次提供這兩個範圍的屬性和流暢的語法來定義類別屬性與基礎資料表的資料行之間的對應。同樣地,在您可以定義索引、 主索引鍵、 身分識別資料行、 預設值,而其他任何基礎資料庫可讓您設定資料行和資料表中。以下是 Region 類別的最小版本︰

public class Region
{
  public Region()
  {
    Languages = "EN";
  }
  [Key]
  public string RegionCode { get; set; }
  public string RegionName { get; set; }
  public string Languages { get; set; }
  ...
}

區域資料表中的所有記錄,會都有三個 nvarchar (max) 資料行 (地區碼、 RegionName 和語言) 和地區碼將會設定為主要索引鍵資料行。此外,任何新建立的執行個體的區域類別必須"EN"設定為 [語言] 屬性的值。這是能夠確保"EN"資料行的預設值時執行程式碼加入新的記錄。不過請注意,Code First 解決方案的建構函式中設定值,以下不會自動新增的任何預設值繫結中的基礎資料庫組態。

命名資料庫

在程式碼第一個方案中,所有資料庫的連接會都通過 DbContext 衍生類別,這會開啟,並適當地關閉連接,同時仍公開為您的程式碼,才能開啟和關閉作業的完整控制權的內容連接。哪些連接字串,而更重要的是,您要如何提供詳細資料的相關詳細資料的參數化的方式?

當您建立的 DbContext 衍生的類別時,您必須提供一個建構函式。以下是很常見的範例︰

public RegionsContext(string conn) : base(conn)
{
  ...
}

DbContext 類別已接受連接字串做為參數,因此最簡單的做法是您鏡像的功能,透過您的衍生類別的建構函式的基礎建構函式的建構函式。有智慧,DbContext 類別包含某個邏輯來處理傳入的字串。假設您傳遞已在此表單名稱 = XXX 任何字串為 XXX 項目內的應用程式組態檔 (也就是 Web 專案的 web.config) 的 connectionstrings 區段中,可以找到實際的連接字串。否則,任何傳遞的字串會假設是要建立之資料庫的名稱。在此情況下,進一步詳細資料的連接字串,例如認證和伺服器位置應該是在組態檔中的 [entityFramework] 區段的 defaultConnectionFactory 區塊中。請注意,每當 Entity Framework 封裝加入 Visual Studio 專案時,會以無訊息模式的組態檔修改為支援 entityFramework 一節。[圖 1 顯示相關的清單中,為了清楚起見有點修改。

[圖 1 範例 Web.config 檔案為已修改以支援 Entity Framework 程式碼第一次

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections>
    <section name="entityFramework"
      type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection,..." />
  </configSections>
    <startup>
      <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
    </startup>
  <connectionStrings>
    <!-- Your explicit connection strings -->
  </connectionStrings>
  <entityFramework>
    <defaultConnectionFactory type=
      "System.Data.Entity.Infrastructure.SqlConnectionFactory,
      EntityFramework">
    <parameters>
    <parameter value="Data Source=(local); Integrated Security=True;" />
    </parameters>
  </defaultConnectionFactory>
  <providers>
    <provider invariantName="System.Data.SqlClient"
      type="System.Data.Entity.SqlServer.SqlProviderServices, ..." />
    </providers>
  </entityFramework>
</configuration>

大部分的尋找第一個程式碼的相關範例根據從組態檔參考或明確傳遞至內容類別,以固定且穩定的連線字串。最後的結果會是第一個程式碼會建立應用程式執行提供的連接字串第一次使用的資料庫。讓我們深入探討此層面。

DbContext 類別支援四個初始化策略,如下所示 [圖 2

[圖 2 Code First 資料庫初始化策略

策略 描述
CreateDatabaseIfNotExists

檢查資料庫是否存在,且如果它找不到其中一個會建立。如果資料庫存在,但有不相容的結構描述,則它會擲回例外狀況。

注意: 這是預設的初始設定式。

DropCreateDatabaseIfModelChanges 如果不存在,請建立資料庫。如果資料庫存在,但具有不相容的結構描述,然後再卸除現有的資料庫,建立一個新。
DropCreateDatabaseAlways 每次執行應用程式現有的資料庫中卸除並重新建立它。
自訂初始設定式

您撰寫出您想要有無其他選項提供行為的自訂初始設定式類別。

注意: 您必須使用此選項,將一些主要的內容加入至資料庫。

 

根據 CreateDatabaseIfNotExists 預設行為,每次建立內容類別時,它會檢查參考的資料庫是否存在,且可連接。如果沒有,它會建立它。如果資料庫存在並可連線到,但沒有公用的版面配置的實體類別與相容的結構描述,然後就會擲回例外狀況。若要移除的例外狀況,您必須編輯實體類別,或更有可能的原因編輯資料庫結構描述可能是透過程式設計介面或 Entity Framework 移轉指令碼的資料庫。

我找到這個選項適用於當應用程式達到的實際執行層級。在開發階段,不過,我偏好 [DropCreateDatabaseIfModelChanges] 選項,基本上是保護您抵禦任何資料庫維護工作︰ 您的調整為適當的實體類別和 Entity Framework 的修正資料庫在您按 f5 鍵,在 Visual Studio 中的下一次。若要啟動您所選擇的初始化策略中,您可以加入下列這一行自訂 DbContext 類別的建構函式︰

Database.SetInitializer<YourDbContext>(
  new DropCreateDatabaseIfModelChanges<YourDbContext>());

請注意,您也可以設定資料庫初始設定式組態檔中,這可能是個好主意,如果您打算使用不同的策略,在生產環境與開發。

總而言之,第一個程式碼可讓您撰寫的應用程式會自動建立所有的資料庫資料表第一次執行它。換句話說,您只需要為複製的檔案與二進位檔,然後啟動它。如果單一客戶的內建系統,這種行為,不過,處於最佳狀態運作。當您有多客戶系統時,的最好的辦法是使用一種安裝程式。

其中一個原因而採取稍微不同的方法是您可能想要以不同的方式,將資料庫命名比方說,您可能想要加入客戶特定前置詞的名稱。[圖 3 顯示這類的命令列公用程式的基本架構。程式會從命令列的客戶前置詞、 格式化為適當的資料庫名稱並再觸發的 DbContext 衍生的類別,會重新建立資料庫,並填入適當的初始資料。

[圖 3 客戶專屬的資料庫名稱

class Program
{
  static void Main(string[] args)
  {
    var prefix = args[0];
                // boundary checks skipped
    var dbName = String.Format("yourdb_{0}", prefix);
    using (var db = new YourDbContext(dbName))
    {
      // Fill the database in some way
    }
  }
}

資料庫的初始填滿

為了容納相同商務網域中的多個客戶的需求而設計的任何系統必須有一些資料表專用儲存選項與不同客戶的喜好設定。以某種方式在安裝軟體時,必須提供這項資訊。實際上,資料庫的初始載入的組件共用的所有安裝,但其中一部分是客戶專用。部分取決於客戶的資料通常從外部來源匯入和需要臨機操作的常式,無論是某種類型的指令碼或編譯的程式碼。根據內容,它甚至可能不出的其他相依性插入機制,來一般化的匯入工具的安裝程式公用程式初始化資料庫內結構的地方思考。靜態資料庫內容是而言,不過,第一個程式碼有臨機操作服務提供。

自訂初始設定式

在初始化過程中,在資料庫的項目資料是必要的您建立的自訂資料庫初始設定式中所述 [圖 2。自訂初始設定式是繼承自 DropCreateDatabaseIfModelChanges 例如預先定義的初始設定式的其中一個類別。這個類別只嚴格要求會覆寫的 Seed 方法︰

public class YourDbInitializer : DropCreateDatabaseAlways<YourDbContext>
{
  protected override void Seed(YourDbContext context)
  {              
    ...
  }
}

在 Seed 方法的實作中,您可以執行任何會使用提供的 DbContext 來存取資料庫的資料表中填入的程式碼。這是它的全部。

如果您計劃多客戶應用程式,定義自訂的初始設定式是一個絕佳移動,因為它提供單一點將重點放入圖案往上各客戶之資料庫的初始表單上。初始設定式是邏輯的一般的 C# 類別,因此它可能會獲得授權,將它連接到特定,可以從只居住地匯入資料片段中使用相依性資料隱碼攻擊工具。

最後,可以停用資料庫初始設定式,因此,資料庫的安裝程式保持完全不同的作業完全 — 或許是由不同甚至管理 IT 或開發維運團隊。若要指示程式碼第一個架構,忽略任何初始設定式,您必須遵循自訂 DbContext 類別的建構函式中的程式碼︰

Database.SetInitializer<YourDbContext>(null);

比方說,這是安全的選項,可使用當您發行更新至現有的系統。停用初始設定式可確保您永遠不會遺失任何在任何現有的資料。

總結

在一天結束時,第一個程式碼可讓多租用戶和多客戶的應用程式撰寫比特別撰寫的已知的組態和用戶端應用程式也不困難。只需要一點指派的連接字串和初始化程序的相關知識。在 Entity Framework 的核心,核心原則保持不變,即使它最終的運作方式的詳細資料會有所不同。特別是,新的 DbContext 類別功能讓您連接資料庫提供者所選擇的內容,並將它傳遞認證及其他任何 OnConfiguring 可覆寫方法。


Dino Esposito 是每個 「 Microsoft.NET:  架構的企業應用程式 」 (Microsoft Press,2014年) 和 [使用 ASP.NET 最新 Web 應用程式] (Microsoft Press,2016年)。.NET 和 Android 平台在 JetBrains,並在世界各地的產業活動的技術推廣人員 Esposito 分享軟體的願景 software2cents@wordpress.com 和 Twitter: @despos

感謝下列 Microsoft 技術專家來檢閱這份文件︰ Andrea Saltarello (andrea.saltarello@manageddesigns.it)
Andrea Saltarello 是企業家及軟體架構設計人員米蘭,義大利,從仍都喜歡撰寫程式碼為真實的專案,以取得有關他的設計決策的意見反應。為培訓講師和喇叭,他已有課程和研討會的幾個讀出的合作跨歐洲 TechEd Europe、 DevWeek 等軟體架構設計人員。他自 2003年已是 Microsoft MVP,而且最近已受命 Microsoft 區域經理。他是熱衷於音樂,並用於第一次 Depeche 模式,與其他已經愛自從接聽 」 的所有項目計數 」。