EF裏的繼承映射關係TPH、TPT和TPC的講解以及一些具體的例子

EF裏的繼承映射關係TPH、TPT和TPC的講解以及一些具體的例子

本章節講解EF裏的繼承映射關係,分爲TPH、TPT、TPC。具體:html

1.TPH:Table Per Hierarchy數據庫

這是EF的默認的繼承映射關係:一張表存放基類和子類的全部列,自動生成的discriminator列用來區分基類和子類的數據。新建一個度假村Resort實體類試試:api

複製代碼

/// <summary>
    /// 度假村類
    /// </summary>
    public class Resort : Lodging  //這裏繼承了Lodging類
    {
        public string Entertainment { get; set; }  //娛樂
        public string Activities { get; set; }  //活動
    }

複製代碼

以前的住宿類Lodging裏有個屬性IsResort表示是否度假勝地,如今能夠註釋掉了,有新的類Resort來繼承Lodging表示是不是度假勝地了,跑下程序最終會生成一張表:app

並無生成Resorts表,而是把Resrot實體類裏的屬性生成到了Lodgings表裏。多了一列discriminator,這個是默認的,用來表示數據來自哪一個類,繼續添加一個插入Lodging表數據的方法:工具

複製代碼

private static void InsertLodging()
        {
            var lodging = new CodeFirst.Model.Lodging
            {
                Name = "Rainy Day Motel",
                Destination = new CodeFirst.Model.Destination
                {
                    Name = "Seattle, Washington",
                    Country = "USA"
                }
            };
            using (var context = new CodeFirst.DataAccess.BreakAwayContext())
            {
                context.Lodgings.Add(lodging);
                context.SaveChanges();
            }
        }

複製代碼

再添加一個插入Resort表數據的方法:性能

複製代碼

private static void InsertResort()
        {
            var resort = new CodeFirst.Model.Resort
            {
                Name = "Top Notch Resort and Spa",
                MilesFromNearestAirport = 30,
                Activities = "Spa, Hiking, Skiing, Ballooning",
                Destination = new CodeFirst.Model.Destination
                {
                    Name = "Stowe, Vermont",
                    Country = "USA"
                }
            };
            using (var context = new CodeFirst.DataAccess.BreakAwayContext())
            {
                context.Lodgings.Add(resort);
                context.SaveChanges();
            }
        }

複製代碼

在Main方法裏調用兩個插入方法,可獲得以下數據:測試

兩個插入的數據都到了一張表裏。Discriminator列表示數據來自哪一列。固然是能夠配置的,這裏就必須使用Fluent API配置了,Data Annotation表示無能爲力,到LodgingMap裏進行配置:ui

this.Map<CodeFirst.Model.Lodging>(l => { l.Requires("From").HasValue("Standard"); });
this.Map<CodeFirst.Model.Resort>(l => { l.Requires("From").HasValue("Resort"); });

生成了咱們指定的From列,數據Standard、Resort分別表示來自Lodging和Resrot表,形象點就是1號酒店是普通酒店,2號就是是度假勝地的酒店:this

固然,這裏甚至能夠把HasValue方法裏的參數設置成True和False,用布爾類型的數據區分普通酒店和度假勝地的酒店更形象,園友lk8167給了一個更形象的普通售貨員和銷售經理的例子rest

2.TPT:Table Per Type

父類和子類在不一樣的表裏。使用Data Annotation配置TPT:

按 Ctrl+C 複製代碼

按 Ctrl+C 複製代碼

或者使用Fluent API配置:

按 Ctrl+C 複製代碼

按 Ctrl+C 複製代碼

注意:上面配置TPH的Fluetn API須要註釋掉在跑程序,那是測試TPH的配置。同時釋放這句的註釋:context.Database.Initialize(true);,這裏沒修改實體,可是也須要從新生成數據庫。最終數據庫是這樣的:

父類和子類實體都有一張表,子表經過主鍵LodgingId找到父表:

3.TPC:Table Per Concrete Type

爲每一個子類創建一個表,每一個與子類對應的表中包含基類的屬性對應的列和子類特有屬性對應的列。一樣以前配置TPT的Fluent API須要先註釋掉,而後咱們經過Fluent API配置下TPC,TPC也沒法用Data Annotation配置:

按 Ctrl+C 複製代碼

按 Ctrl+C 複製代碼

生成的數據庫:

可見,子類Resorts類也有了基類的全部屬性。

注意:爲了方便測試生成TPC,我註釋了全部Lodging表的導航屬性,主要是和Destination的一對多關係、Destination類也須要註釋掉Lodging屬性和Fluent API關係配置,不然程序跑起來會報DataException錯:
An exception occurred while initializing the database. See the InnerException for details.

你們下載demo使用的時候也須要先註釋掉Lodging類的導航屬性。固然不註釋想保留也能夠,必須設置外鍵爲可空類型,具體請參考Programming Entity Framework: Code First 第五章 Avoiding Mapping Exceptions with TPC

講了這幾種方式配置繼承映射,實際項目中應該用哪一個呢?

  1. 不推薦使用TPC(Type Per Concrete Type),由於在TPC方式中子類中包含的其餘類的實例或實例集合不能被映射爲表之間的關係。你必須經過手動地在類中添加依賴類的主鍵屬性,從而讓 Code First感知到它們之間的關係,而這種方式是和使用Code First的初衷相反的;
  2. 從查詢性能上來講,TPH會好一些,由於全部的數據都存在一個表中,不須要在數據查詢時使用join;
  3. 從存儲空間上來講,TPT會好一些,由於使用TPH時全部的列都在一個表中,而表中的記錄不可能使用全部的列,因而有不少列的值是null,浪費了不少存儲空間;
  4. 從數據驗證的角度來講,TPT好一些,由於TPH中不少子類屬性對應的列是可爲空的,就爲數據驗證增長了複雜性。

摘自這裏,本文源碼

本系列文章結束,主要講解了EF裏如何使用Code First的方式配置數據庫,基本上都是手寫的配置,其實你們可能已經想到會有工具能夠自動配置這些關係了,對了,就是EF Power Tools。這個工具至關智能,能夠直接配置出全部的關係。不過我的仍是建議關係很少的話本身手寫Fluent API來配置。

另外,前面配置了那麼長時間的一對多、多對多等各類關係。配置好了如何用EF對這些數據進行增查改查呢?後續還會有系列文章講解EF是如何操做數據庫的,請保持關注。

EF Code First 系列文章導航
  1. EF Code First 初體驗
  2. EF裏的默認映射以及如何使用Data Annotations和Fluent API配置數據庫的映射 本節源碼
  3. EF裏Guid類型數據的自增加、時間戳和複雜類型的用法 本節源碼
  4. EF裏一對1、一對多、多對多關係的配置和級聯刪除 本節源碼
  5. EF裏的繼承映射關係TPH、TPT和TPC的講解以及一些具體的例子 本節源碼
相關文章
相關標籤/搜索