【譯著】Code First :使用Entity. Framework編程(2)


第二章:Code First概覽

如果你使用第一、二版的EF框架工作過,你會回想起書中的業務案例:Break Away Geek Adventures, 簡稱BAGA。BAGA共享了很多像我們這樣的奇客的冒險旅行。但是幾年過去了,業務又在增長,到了需要更新應用程序的時候了。既然BAGA為軟件奇客服務,他們不能拒絕嘗試使用新技術,如EF的Code First.

在這一章里,我們從一個小例子來開始學習Code First的默認行為,然后逐步向這個例子里添加影響這種行為的信息。

我們將開始於BAGA業務域的一個小片斷:包括我們旅行的目的地和我們的奇客們在這次旅行的住所。

Code First的美妙在於域類的定義代碼與EF數據模型所依賴的代碼是一樣的。我們只需要開始於代碼就可以了,例2-1,分別展示了Destination類和Loadging類。在開始的案例中,我們要保持類的簡潔;這些類包含了一些自動屬性,並沒有什么邏輯。

Example 2-1. The domain model

public class Destination

{

public int DestinationId { get; set; }

public string Name { get; set; }

public string Country { get; set; }

public string Description { get; set; }

public byte[] Photo { get; set; }

public List<Lodging> Lodgings { get; set; }

}

public class Lodging

{

public int LodgingId { get; set; }

public string Name { get; set; }

public string Owner { get; set; }

public bool IsResort { get; set; }

public Destination Destination { get; set; }

}

 

Destination類描述了一個特定的BAGA旅行的目的地,對於任何給定的目的地,從Aspen到Zimbabwe,BAGA都會安排各種住所,從床位到五星級酒店,以便到時暫住。因此目的地對象要包含一個或多個居所,使用了List<lodging>來表達;

EF域類介紹

本質上,這些類與EF和Code First無關。這里只簡單描述了域的一部分。 

為了讓EF框架能夠找到這些類,需要使用EF框架的context來服務、管理和持久化數據至數據庫。EF框架有兩種context工具可供選擇,一個是ObjectContext,這一工具從EF第一次發布就一直是EF框架的一部分,而隨着EF4.1的發布,伴隨Code First推出輕量級的DbContext。兩種工具都可選用,但更通用(推薦)的是使用新的DbContext,也就是我們馬上就要使用的。本書第7章,你將會學習如何使用ObjectContex進行Code First.

我們的BreakAwayContext類,就繼承自DbContext,可以獲得DbContext的所有功能。除此以外,還需要返回Destination類和Lodging類的可查詢數據集DbSets,以暴露類中的屬性

Example 2-2 The BreakAwayContext class

public class BreakAwayContext : DbContext

{

public DbSet<Destination> Destinations { get; set; }

public DbSet<Lodging> Lodgings { get; set; }

}

 

 這個小小的類就代表了你在應用程序中使用的完整的數據層.感謝DbContext,你可查詢,修改,跟蹤和保存目的地和住所數據.下面創建一個控制台程序使用這個數據層來做一些工作,你會看到我們並非言過其實.

將片斷放入程序中

為了查看有關行為,下面將帶您實現一個小的VS解決方案,在此你可將這些類放進去,然后創建一個簡單的控制台程序來測試你的新數據層.確保你已經開始了正確的路徑,本示例將把應用程序的各個層組織在不同的項目中.

1.在VS中創建一個新的解決方案;

2.添加一個類庫項目到解決方案,命名為Model.

3.在這個項目里,添加一個新的類命名為Destination.

4.修改Destination類以使其與例2-3一致:

Example 2-3. The Destination class

using System.Collections.Generic;

namespace Model

{

public class Destination

   {

public int DestinationId { get; set; }

public string Name { get; set; }

public string Country { get; set; }

public string Description { get; set; }

public byte[] Photo { get; set; }

public List<Lodging> Lodgings { get; set; }

    }

}

 

 

5.添加另一個類,命名為Lodging,使其與例2-4一致.

Example2-4.The Lodging class

namespace Model

{

public class Lodging

  {

public int LodgingId { get; set; }

public string Name { get; set; }

public string Owner { get; set; }

public bool IsResort { get; set; }

public Destination Destination { get; set; }

  }

}

這就是Model項目的內容.現在,轉到數據層,因為域類尚未連接到EF框架上,我們數據層將完全依賴於EF框架.

小貼士:將NuGet安裝到VS中就可以將類庫方便地添加到項目中.在第1章您已學到EF可以通過NuGet獲取.為了完成如下步驟,你需要為VS安裝NuGet擴展.為了安裝NuGet,選擇工具--擴展管理….會出現擴展管理對話框,然后查找NuGet.選擇NuGet擴展管理包,點擊下載按鈕,按照提示安裝.

一旦安裝完成,您就可以以一種新的方式使用VS了.你可通過VS的工具菜單--添加類庫來添加所需的類庫,另一種方式是使用上下文菜單來添加,方法是在解決方案的指定項目上點擊右鍵.在下面的操作步驟中,我們使用后者

1.添加另一個類庫項目,命名為DataAcess;

2.在項目資源管理器中右鍵單擊新建立的項目選擇"Add Livray Package Reference"

3.在彈出的對話框中,選擇Online,並搜索Entity Framework;

4.在EF安裝包上點擊安裝按鈕,這將把Code First的運行時組件(EntityFramework.dll)添加到你的項目中;

5.右鍵單擊新的項目並選擇添加引用;

6.選擇項目選項卡將Model proect加入.這將會使context能夠訪問剛剛在Model Project上創建的域類;

7.添加一個新類,BreakAwayContext到項目中;

8.配置這個新類如代碼2-5;

Example 2-5. The BreakAwayContext class

 

 

using System.Data.Entity;

using Model;

namespace DataAccess

{

public class BreakAwayContext : DbContext

   {

public DbSet<Destination> Destinations { get; set; }

public DbSet<Lodging> Lodgings { get; set; }

   }

}

 

注意類頂部的using語句.一個是System.Data.Entity命名空間.這個命名空間使得你可以訪問DbContext和DbSet類;這可能有些令人困惑,命名空間為EntityFramework.dll的程序集是 EntityFramework.dll,而不是System.Data.Entity.dll。System.Data.Entity.dll包含了EF框架的核心,已經是.Net框架的一部分.

現在你的數據訪問層已經建好了.可以測試你的數據訪問層了.

請等一下,我們還沒有告訴數據訪問層數據庫在哪.還沒有連接字符串,沒有配置文件,沒有關聯的數據庫.我們要在此利用Code First的第一個功能,數據庫初始化.Code First有一系列的步驟來找到數據庫並且初始化它.我們現在先使用默認行為,在后面第6章,將會學到更多關於數據庫初始化的知識。當然,也可以開始於一個現存的數據庫,只是我們現在不這么做。

1.添加一個新的控制台應用程序項目到解決方案,命名為BreakAwayConsole.

2.右鍵單擊新的項目,設置為啟動項目;

3.右鍵單擊項目,選擇添加類庫引用,添加對EF框架的引用;

4.再次右鍵單擊項目,選擇添加引用,將Model和DataAcess項目添加至項目;

5.在新項目中,打開Program類;

6.添加兩個using語句在文件頂部:

using Model;

using DataAccess;

7.在類中添加一個方法,命名為InsertDestination(代碼2-6);

Example 2-6 The InsertDestination Methoed

private static void InsertDestination()

{

var destination = new Destination

   {

Country = "Indonesia",

Description = "EcoTourism at its best in exquisite Bali",

Name = "Bali"

   };

using (var context = new BreakAwayContext())

  {

context.Destinations.Add(destination);

context.SaveChanges();

  }

}

 

8.在類中調用這個方法(代碼2-7)

Example 2-7. Calling the InsertDestination method

static void Main()

{

InsertDestination();

}

完成!對這兩個域類你只用了少量代碼,兩行數據訪問類以及這個小的應用類,你已經開始准備運行應用程序了。

這個控制台程序並不會顯示任何信息.有趣的是發生數據庫里的事情:數據庫剛才並不存在。

Code First 通過檢視Destination 和 Lodging 類確定了數據模型,然后根據類屬性推斷出數據庫的架構模型.既然我們沒有提供連接字符串,它就使用默認的約定,查找本地SQL Server Express實例(localhost\SQLEXPERSS)作為數據庫宿主,然后以context類的類名DataAcess.BreakAwayContext匹配數據庫名.沒有找到這樣的數據庫,Code First就創建它,然后使用它在模型中發現的類依據約定創建表和表的字段。

我們來看看SQL Server Express中Code First創建的數據庫(圖2-1).

可以看到,DataAccess.BreakAwayContext 有三個表:Destinations ,Lodgings和EdmMetadata,后者用於Code First的數據庫初始化,后面我們會提到.

關於表,構架,和字段名的約定

 Code First 約定表名使用EF框架的復數化服務(由EF4引入),即使用英語語法的類名復數形式來命名表名。(這個功能可以關閉,見第7章,譯者注)默認情況下,每個表都使用dbo構架創建。Code First 屬性映射的列使用與類中屬性一致的名字命名.

關於主鍵的約定

再次觀察數據庫表,你會找到Code First已經使用的默認規則。例如,Code First知道Detination類的DestinationId和Lodging類的LodgingId意思是鍵值,然后將這些鍵映射為數據庫的主鍵。注意這些鍵都是非空主鍵(PK,notnull)。Code First默認約定將命名為Id或[類名]Id的屬性視為類的鍵。DestinationId 和LodgingId顯然符合這一規則。由於這些屬性都是整型類型,Code First還會將它們配置為數據庫的標識字段。這表示在插入數據時數據庫會為這一字段自動生成值。

字符串屬性的約定

字符串約定為映射到不限長度的非空列中。由數據庫引擎來負責確定映射到何種類型。對於SQL Server而言,默認數據類型為nvarchar(max)。這就是你在圖2-1看到的所有的字符串屬性都映射成了nvarchar(max)列的緣故---Destination.Name,Country,Description等等.--同時還允許存儲空值;

針對Byte數組的約定

Destination類有一個Photo屬性,定義為byte[].Code First 約定byte數組映射到不限長度的非空列中.對SQL Server而言就是varbinary(max)類型.

布爾值的約定

Lodging類中的IsResort屬性是一個bool類型.由於bool是一個值類型,不能分配給其一個null值.Code First強制要求此列不能為空.對SQL Server而言將bool屬性映射為bit 數的庫類型.

一對多關系的約定

一個目的地會有很多居所,因此Destination類有一個List<Lodging>屬性允許你獲取特定目的地的所有居所信息.同時,Lodging類也有一個Destination類型的屬性,,因此你可看到某一居所與某一特定的目的地相連接.Code First將這種情況視為一對多關系,約定Lodging表有一個外鍵約束目的地與居所間的所有關系. 

注意盡管在Lodging類中沒有外鍵屬性指向Destination類(如DestinationId),Code First仍然使用默認規則創建了一個,形如[Name of navigation property]_[Primary Key of related class](即Destination_DestinationId),這是Code First所為。使得EF框架知道在從數據庫中查詢或保存時要使用外鍵. 

在目的地和住宿類提供給Code First的導航屬性不是一個,而是兩個。如果我們只提供了其中之一,關系仍然明顯,Code First還是會在數據庫中創建外鍵。還有很多提供外鍵的約定適用於某些場景,如多對多關系等,在后面我們會深入討論。

使用配置來覆寫約定

正如在第1章學到的,Code First允許你覆寫約定,方法是添加配置.可以選擇使用Data Annotation的特性標記也可以使用強類型的Fluent API來配置. 

您提供的任何配置將會作為模型的一部分,EF框架使用此模型在運行時解析數據。這不僅影響數據庫構架,也會影響DbContext內置的驗證功能。例如,如果你告訴Code First一個屬性是必備的,驗證API將讓你知道,如果該屬性沒有被填充的后果。在后續我們將看到這一行為。

Data Annotations是最簡單的配置方式,直接應用到你的類和類屬性上。這些特性位於System.ComponentModel.DataAnnotations命名空間,目前分布在System.ComponentModel.DataAnnotations.dll和EntityFramework.dll兩個程序集中。在未來版本的.NET Framework中,EntityFramework.dll中的Annotations將遷移到System.ComponentModel.DataAnnotations.dll。所以需要在域類的項目中引用上述程序集(取決於您使用的Annotations)。注意Data Annotations能夠完成常用的配置,但並非所有Code First配置都可以使用Data Annotation來完成。一些情況下只能使用另一種風格的配置方式:Fluent API。

因為Code First沒有自動發現Destination和Lodging類中的某些意圖,需要用一些Data Annotations提供額外的配置細節。

小貼士:在C#和Visual Basic應用特性

如果你第一次使用特性,在C#中,特性應使用方括號。例如,使用Annotation 特性Key,在c#中使用[Key],而在Visual Basic中,使用尖括號(<Key>)。當一個特性使用參數時,在C#中是表達了一個等號表達([Table(Schema="baga")]),而Visual Basic使用冒號等號表示(<Table(Schema:="baga")>) 要知道.NET代碼中使用特性的更多信息,請參閱MSDN主題"應用特性",在http://msdn.microsoft.com/en-us/library/bfz783fz.aspx。

讓我們從Destination類開始.關於這個類我想要作三個調整:

  • 必須提供目的地的名字
  • 限制描述字段的文本內容在500個字符以內
  • 保存照片到SQL Server數據庫應為image類型,而不是varbinary(max).

上述需要的Data Annotations特性有兩個包含在System.ComponentModel.DataAnnotations.dll程序集中,這是.Net 4的一部分,有一個包含在EntityFramework.dll程序集里,所以需要對兩個程序集都要添加引用:

1.在Model項目中,添加對System.ComponentModel.DataAnnotations 程序集的引用.

2.通過類庫包裝引用添加對EntityFramework程序集的引用.

記住:你必須對每個項目都運行NuGet類庫添加向導,即使類庫包已經添加到解決方案中的某個項目中.使用同樣的步驟將EntityFramework.dll添加到DataAccess項目中.

3.在Destination類頂部,添加System.ComponentModel.DataAnnotations命名空間.

4.修改類如代碼2-8所示Example 2-8. Modified Destination class

using System.Collections.Generic;

using System.ComponentModel.DataAnnotations;

namespace Model

{

public class Destination

   {

public int DestinationId { get; set; }

[Required]

public string Name { get; set; }

public string Country { get; set; }

[MaxLength(500)]

public string Description { get; set; }

[Column(TypeName = "image")]

public byte[] Photo { get; set; }

public List<Lodging> Lodgings { get; set; }

   }

}

 

Required特性標記不需要附加信息,而MaxLength和Column特性均需要提供參數.這些參數對如何映射到數據庫的列進行了明確。我們想要圖片儲存在SQL Server的image字段里.

小貼士:只要有可能強制將數據庫中字段的類型設定為指定類型(例如將byte[]強制指定為image),你可配置數據類型特性。所有的三個特性將會影響數據庫的構架,其中之二,Required和MaxLength,也被用於EF框架的驗證之用.在觀察效果之前,也對Lodging類作些類似的修改.

Annotation特性標記可組合使用,也就是在一個類或屬性上可以附加多個annotations特性.我們准備在Lodging.Name屬性附加多個配置特性. 

添加下述三個注解到Lodging類的Name屬性:

[Required]

[MaxLength(200)]

[MinLength(10)]

MinLenght是一個有趣的annotation特性.MaxLength在數據庫有對應的含義,而MinLength並不有.MinLength將會用於EF框架的驗證,並不會影響數據庫. 

MinLength只能通過Data Annotations來進行配置,在Fluent API 中無對應項.

 理解模型變化如何影響數據庫初始化

如果再次運行控制台程序,你會得到一個InvalidOperationException異常.我們剛剛對模型作的修改並沒有什么錯誤,問題在於Code First數據庫初始化的默認行為.因此我們需要在繼續探索配置時需要修復這些問題. 

下面是異常的信息:

The model backing the 'BreakAwayContext' context has changed since the database was created. Either manually delete/update the database, or call Database.SetInitializer with an IDatabaseInitializer instance. For example, the DropCreateDatabaseIfModelChangesstrategy will automatically delete and recreate the database, and optionally seed it with new data.

自上次數據庫創建以來,'BreakAwayContext'的上下文已經發生變化.要么手工刪除或更新數據庫,要么調用IDatabaseInitializer接口的實例 Database.SetInitializer.例如 DropCreateDatabaseIfModelChanges策略將自動刪除和再創建數據庫,並且可選擇使用新數據作為種子.

.默認情況下,Code First只有當數據庫不存在的時才創建數據庫,但目前數據庫已經有了,該怎么辦呢? 

是否還記得EdmMetadata表?如果沒有,回頭看一下圖2-1.這個表包含了Cord First創建數據模型的部分快照。默認情況下,它會伴隨着Code First第一次使用模型建立數據庫時創建。然后它就會將表中的版本信息與內存中的模型相比較(這可以從EdmMetadata表中讀出)。當Code First識別到上一模型的元數據模型與新建立的模型不匹配,就無法將模型映射到數據庫.

您有很多選擇.一個是簡單刪除數據庫(包括其中的所有數據),然后讓Code First使用默認規則(無數據庫--創建新數據庫)來使用更新模型創建數據庫.這可能很痛苦,特別是你在開發過程中,可能會遇到某些情況導致文件鎖定而無法刪除.另一種方法,我們馬上要用,Code First在遇到模型變化時有一套初始化策略可供使用,該行為刪除數據庫並重建,默認是封裝在名為CreateDatabaseIfNotExists的類中,你可告知正在執行中的程序(本處是指控制台程序)使用哪個策略。

修改Main方法使之與例2-9一樣.也需要在添加一個using語句,引用System.Data.Entity.

Example 2-9. Adding Database Initialization to the Main method

static void Main(string[] args)

{

Database.SetInitializer(

new DropCreateDatabaseIfModelChanges<BreakAwayContext>());

InsertDestination();

}

 在此代碼中我告訴Code First使用初始化器並且指定使用何種策略.(這里使用了DropCreateDatabaseIfModelChanges)應用於上下文(BrakAwayCOntext).現在當你返回應用程序,Code First將識別新舊模型的區別,通知初始化器,刪除和重建數據庫.

如果你已經在其他地方打開了數據庫表讀取數據,(例如,在Visual Studio的服務器資源管理器),Code First將不能夠刪除數據庫。在這種情況下,在EF框架嘗試刪除時會有一個延遲,最終因為無法刪除而拋出一個異常。似乎這樣做太繁瑣,特別是當我在用戶組和會議展示時。我遇到的一個常見的場景是,我已打開了SQL Server Management Studio(SSMS)中,對數據庫進行一些查詢。你不得不關閉SSMS的數據庫完全釋放對數據庫的鎖定。

Destination類之Destinations表有三個可見的改變,Name設定為必須,在數據庫表現為非空字段.Description現在是nvarchar(500)而不再是max,Photo也已經是一個image數據類型.Lodging表也得到影響,Name現在限制為200個字符且為非空型,第三個annotation:MinLength在數據庫構架中沒有等效值,因此在此忽略.但是,EF框架將會對此進行驗證.

 Data Annotations和前端驗證提示

NET 4中引入的Data Annotations,可以用於ASP.NET(含.Net MVC)作為用戶界面的動態數據驗證工具來使用。許多Code First 使用的annotations特性標記都來自源於System.ComponentModel.DataAnnotations程序集。因此,這些數據驗證功能是.Net程序集的的內置特性。

例如,"Required"特性在.NET4的程序集中,而不在EntityFramework.dll程序集里。因此,如果你在MVC應用程序中使用的Code First類,並且忽略填寫一個必須輸入的屬性,MVC用戶界面驗證會響應,你可以在圖2-3看到。

DbContext還提供了一個驗證API,具有服務器端驗證的能力,這與使用Data Annotations特性標識還是使用Fluent API來配置類是沒有關系的。但是,使用Data Annotations時,MVC與特性更好地配合,實現一些驗證API的功能。驗證API的細節內容不包括在這本書中,本書的重點在於Code First建模,你可在另一本書:Entity Framework:DbContext找到與驗證API有關的信息。

使用Fluent API 配置Code First

使用Data Annotations配置很簡單,也可能是你想要的。但是Data Annotations只能獲得一部分配置的功能。這時,Fluent API可以提供更多的功能,基於這個原因你可能會願意用它.

小貼士:Fluent API是什么?

Fluent API並非專用於Code First或EF框架。Fluent API的基本思路是使用鏈方法調用程序代碼,這樣代碼很容易被開發者所閱讀。每一個調用的返回類型都定義為下個調用的有效方法.例如,在Code First的Fluent API中,你可以使用Entity方法選擇一個實體來配置.智能感知將會顯示出所可以用來配置的方法.如果你使用屬性方法選擇屬性來配置,你就看到所有為特定屬性所配置的方法.

還有另一個原因解釋為什么開發者首選Fluent API。在將標記應用到你的美妙域類上時,需要定義越來越多的煩人的標記。目前還只是一些驗證邏輯,當你學到更多Data Annotations配置特性的時候,你就會發現需要更多的信息指導類如何映射到數據庫。如果你喜歡清潔的類,不想讓類包含那么多的標記,就可以選擇Fluent API。Code First的一個優勢就是能夠使用自己的類構建EF框架,一個充斥着數據庫表名或列類型的類顯然不夠簡潔,Fluent API解決了這一問題,我們來看這是如何實現的。

小貼士:跟隨Data Annotations還是跟隨Fluent API  ?

在本書后續內容中,你將會看到很多例子來說明如何配置映射,有Data Annotations的,也有使用Fluent API的.

許多映射只能通過Fluent API獲得.如果你在VS中跟隨我們學習,強烈推薦您創建兩個單獨的解決方案。否則,當使用了Data Annotation中還想看看在Fluent API中同樣的配置效果,你就不得不注釋掉有關代碼。然后當你使用另一個Data Annotation特性標記,你又不得不注釋掉Fluent API代碼.在注釋與取消注釋之間來回調整,萬一出現錯誤就會導致拋出異常,要么是配置重復要么是配置丟失,可能會非常麻煩。

這就意味着在創建新類或添加新方法時需要進行許多必要的復制/粘貼操作.也意味着Data Annotations 只能應用於一個解決方案而Fluent 配置被強制用於另一個.  

如果你遵循此建議,還有一個附加的建議.確保在兩個解決方案使用不同的命名空間。如果其中一個解決方案使用了DataLayerForAnnotations命名空間,其數據庫將為DataLayerForAnnotations.BrakeAwayContext。另一解決方案使用了DataLayerForFluent,命名空間,其數據庫將為DataLayerForFluent.BrakeAwayContext。你會看到有兩個獨立的數據庫,很容易理解哪個解決方案影響了哪個數據庫。

DbContext首先在類中查找可以獲取的信息。這時,context已經准備好解析模型,但對開發者來說有一個機會來中斷context和執行附加配置的連接.這得益於DbContext.OnModelCreating方法,這是在模型創建前被上下文所調用的方法。方法是虛擬的,因此你可以覆寫並加入你自已的邏輯代碼.這就Fluent API進行配置的入口.

此方法的聲明方式如下: 

 

protected  override  void OnModelCreating(DbModelBuilder modelBuilder)

 提供給OnModelCreating的參數DbModelBuilder是你需要添加配置的類。DbModelBuilder使用泛型和lambda表達式,所以編碼是強類型的可以協助您進行配置的設置。首先要告訴DbModerBuilder對哪個類(實體)實施配置:

 

modelBuilder.Entity<Destination>() ;

 你可以配置類映射到數據庫的表名:

 modelBuilder.Entity<Destination>().ToTable("a_table_name");

你也可配置類的屬性.如果想要配置屬性,應進一步演進:

modelBuilder.Entity<Destination>()
.Property(d => d.Description).HasMaxLength( 500);

代碼2-10重寫了前面使用data annotations建立的配置。OnModelCrating是DbContext的一個方法,請確保它在BrakAwayContext類里。

Example 2-10. Configuring with the Fluent API

protected  override  void OnModelCreating(DbModelBuilder modelBuilder)
 {
   modelBuilder.Entity<Destination>()
    .Property(d => d.Name).IsRequired();
   modelBuilder.Entity<Destination>()
    .Property(d => d.Description).HasMaxLength( 500);
   modelBuilder.Entity<Destination>()
   .Property(d => d.Photo).HasColumnType( " image ");
   modelBuilder.Entity<Lodging>()
   .Property(l => l.Name).IsRequired().HasMaxLength( 200);

  } 

如果你疑惑HasMinLength哪里去了,在Fluent配置方法里沒有最小長度的配置,因為這不會對數據庫的行產生影響.

除非要配合使用Data Annotations 和 Fluent API為了保持代碼一致最好選擇其一。為了讓代碼更流暢,我們已經移除了所有的Data Annotation標記.實際上Model項目也不需要對System.Component Model.DataAnnotations 或者EntityFramework程序集的引用.

再次運行代碼,Code First將對比模型和數據庫中的EdmMeta表,盡管我們修改了配置代碼,最終結果還是一樣的.同樣的destination再次加入數據庫中結束與匹配的記錄.在圖2-4你可以看到復制到的數據.

組織Fluent配置

如果你有很多配置需要執行,OnModelCreating 可能很快不堪重負(代碼太多)。應該使用位於EntityTypeConfiguration的實體類來分組配置,然后在OnModelCretaing方法中告訴DbModelBuilde有些實體類r。DbModelBulider有一個Configruation屬性可以來增加EntityTypeConfigurations(實體類型配置).

例2-111展示了對Destinaton類和Lodging類的分組情況:

Example 2-11. Organizing configs into separate EntityTypeConfiguration classes

using System.Data.Entity.ModelConfiguration;
using Model;
public  class DestinationConfiguration :
EntityTypeConfiguration<Destination>
 {
     public DestinationConfiguration()
     {
        Property(d => d.Name).IsRequired();
        Property(d => 
         .Description).HasMaxLength( 500);
        Property(d => d.Photo).HasColumnType( " image ");
     }
 }
public  class LodgingConfiguration :
EntityTypeConfiguration<Lodging>
 {
     public LodgingConfiguration()
    {
        Property(l => l.Name).IsRequired().HasMaxLength( 200);
    }
 }

  

這些代碼在OnModelCreating方法內部的時候,由DbModelBuilder開始,后面跟着Entity方法來確定哪個實體進行配置。在EntityConfiguration類中,是由繼承於EntityTypeConfiguration類的類開始的,這里的實體類型已經指定。例如,modelBuilder.Entity<Destination>().Property這個語句是對屬性進行設置,而調用的modelBuilder.Entity<Destination>()實際上是創建了一個EntityTypeConfiguration<Destination>對象並返回給你,然后在屬性上配置。所以無論使用哪種方式,訪問的是同一個API。 

代碼2-12,你會看到修改的OnModelCrating方法,來使用這些類.

Example 2-12. Adding the configuration classes in OnModelCreating

protected  override  void OnModelCreating(DbModelBuilder modelBuilder)
  {
    modelBuilder.Configurations.Add( new DestinationConfiguration());
    modelBuilder.Configurations.Add( new LodgingConfiguration());

   }

隨着我們轉向Fluent配置的例子,我們有時會將配置放在EntityTypeConfiguration類,有時放置在modelBulider中。這僅僅是為了讓你繼續看到這兩種語法。但是,在最終產品中,很顯然不能混用配置。你更希望有一個統一的方式,無論是將所有配置都寫在OnModelCrating方法內部還是組織在EntityTypeConfiguration類中。你會看到有幾個配置操作不是類型相關的,必須要直接在OnModelCreating方法中調用。 

小結

本章對Code First作了基礎介紹.我們看到Code First的約定規則非常智能,能夠通過類的構建獲知您的意圖。當約定無法正確推斷時,你需要使用配置明確控制Code First如何構建模型和數據庫構架。我們介紹可以直接在類上采用Data Annotations的特性來實現配置。而對那些更願意讓域類獨立的情形,你還學到可以使用替代的Fluent API在DbContext類中來實施配置. 

Code First 可以自動為你構建數據庫。你已經看到如何施加控制到其響應以對模型作出調整。期待重建數據庫來匹配新的模型.現在你應該已經喜歡上了Code First,我們將進一步深入。擴展模型,學習使用Code First的來龍去脈.


 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM