第 2 部分:建立領域模型

作者:Rick Anderson

下載已完成的專案

加入模型

有三種方式可使用 Entity Framework:

  • 資料庫優先:您從資料庫開始,Entity Framework 會產生程式碼。
  • 模型優先:您從視覺模型開始,而 Entity Framework 會產生資料庫和程式碼。
  • 程式碼優先:您從程式碼開始,Entity Framework 會產生資料庫。

我們使用的是程式碼優先方法,因此首先將領域物件定義為 POCO (單純的 CLR 物件)。 使用程式碼優先方法時,領域物件不需要任何額外的程式碼來支援資料庫層,例如交易或持續性。 (具體來說,他們不需要繼承自 EntityObject 類別。) 您仍然可以使用資料註釋來控制 Entity Framework 建立資料庫架構的方法。

由於 POCO 不會攜帶任何描述資料庫狀態的額外屬性,因此可以輕鬆地序列化為 JSON 或 XML。 不過,這不表示您應該一律將 Entity Framework 模型直接公開給用戶端,如稍後在本教學課程中所示。

我們將建立下列 POCO:

  • Products
  • 訂單
  • OrderDetail

若要建立每個類別,請在 [方案總管] 中,以滑鼠右鍵按一下 [模型] 資料夾。 從操作功能表中,選取 [新增],然後選取 [類別]。

[模型] 資料夾 [方案總管] 功能表的螢幕擷取畫面。[新增] 功能表會隨即開啟,並反白顯示 [類別] 選項。

使用下列實作新增 Product 類別:

namespace ProductStore.Models
{
    using System.ComponentModel.DataAnnotations;

    public class Product
    {
        [ScaffoldColumn(false)]
        public int Id { get; set; }
        [Required]
        public string Name { get; set; }
        public decimal Price { get; set; }
        public decimal ActualCost { get; set; }
    }
}

根據慣例,Entity Framework 會使用 Id 屬性做為主要索引鍵,並將它對應至資料庫資料表中的識別欄位。 當您建立新的 Product 執行個體時,將不會設定 Id 的值,因為資料庫會產生值。

ScaffoldColumn 屬性會告訴 ASP.NET MVC 在產生編輯器表單時略過 Id 屬性。 Required 屬性是用來驗證模型。 它會指定 Name 屬性必須是非空白字串。

新增 Order 類別:

namespace ProductStore.Models
{
    using System.Collections.Generic;
    using System.ComponentModel.DataAnnotations;

    public class Order
    {
        public int Id { get; set; }
        [Required]
        public string Customer { get; set; }

        // Navigation property
        public  ICollection<OrderDetail> OrderDetails { get; set; }
    }
}

新增 OrderDetail 類別:

namespace ProductStore.Models
{
    public class OrderDetail
    {
        public int Id { get; set; }
        public int Quantity { get; set; }
        public int OrderId { get; set; }
        public int ProductId { get; set; }

        // Navigation properties
        public Product Product { get; set; }
        public Order Order { get; set; }
    }
}

外部索引鍵關聯性

訂單包含許多訂單詳細資料,而每個訂單詳細資料則指稱單一產品。 為了表示這些關聯性,OrderDetail 類別會定義名為 OrderIdProductId 的屬性。 Entity Framework 會推斷這些屬性代表外部索引鍵,並將外部索引鍵約束條件新增至資料庫。

Orders、Products 和 OrderDetails 類別的 Visual Studio 功能表螢幕截圖畫面。

OrderOrderDetail 類別也包含「navigation」屬性,其中包含相關物件的參考。 根據訂單,您可以遵循導覽屬性,依序瀏覽至產品。

立即編譯專案。 Entity Framework 會使用反映來探索模型的屬性,因此需要編譯的組件才能建立資料庫架構。

設定媒體類型格式器

當 Web API 寫入 HTTP 回應本文時,媒體類型格式器是序列化資料的物件。 內建格式器支援 JSON 和 XML 輸出。 根據預設,這兩個格式器都會依值序列化所有物件。

如果物件圖形包含循環參考,依值序列化會產生問題。 這正是 OrderOrderDetail 類別的情況,因為每個類別都有另一個的參考。 格式器會遵循參考、依值寫入每個物件,並以圓形為單位。 因此,我們需要變更預設行為。

在 [方案總管] 中,展開 [App_Start] 資料夾,然後開啟名為 WebApiConfig.cs 的檔案。 將下列程式碼新增至 WebApiConfig 類別:

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        config.Routes.MapHttpRoute(
            name: "DefaultApi",
            routeTemplate: "api/{controller}/{id}",
            defaults: new { id = RouteParameter.Optional }
        );

        // New code:
        var json = config.Formatters.JsonFormatter;
        json.SerializerSettings.PreserveReferencesHandling =
            Newtonsoft.Json.PreserveReferencesHandling.Objects;

        config.Formatters.Remove(config.Formatters.XmlFormatter);
    }
}

此程式碼會將 JSON 格式器設定為保留物件參考,並完全從管線中移除 XML 格式器。 (您可以將 XML 格式器設定為保留物件參考,但還需要多一點操作,且此應用程式只需要 JSON。如需詳細資訊,請參閱處理循環物件參考。)