Entity Framwork CodeFirst 學習筆記三:使用復雜類型


上一篇,主要學習了一些CodeFirst 中修改默認規約的基本配置。在文章最后,出現了個新的名詞:復雜類型。什么是復雜類型呢?

書中說道:“復雜類型也可視作值類型(?)可以作為附加屬性添加到其他類。復雜類型與實體類型的區別在於復雜類型沒有其自己的鍵。它是依賴於其"宿主"類型跟蹤變化 和持久化。一個沒有Key屬性的類型,並且作為屬性映射到一個或多個類型中,Code First就會將其視作為復雜類型。Code First將預設復雜類型的屬性出現在宿主類型映射到數據庫的表中。”

說簡單一點就是,項目中有個類A,這個A,會被其他類引用到比如:實體類B 和 實體類C,但是建立數據庫的時候,我們不想為這個分割類A建立表,而是把A類中的屬性等建立到 B 和 C 映射的表中,這時候,我們管 A 叫做復雜類型。

 來看一下書中的解釋和例子:

比如有如下類:

public class Person
{
     public int PersonId { get; set; }
     public int SocialSecurityNumber { get; set; }
     public string FirstName { get; set; }
     public string LastName { get; set; }
     public string StreetAddress { get; set; }
     public string City { get; set; }
     public string State { get; set; }
     public string ZipCode { get; set; }
}

 這時候,增加Address類作為分割類,不僅可以簡化Person類,而且還可以提高Address 的利用,分離后的代碼如下:

public class Address
{
  public int AddressId { get; set; }
  public string StreetAddress { get; set; }
  public string City { get; set; }
  public string State { get; set; }
  public string ZipCode { get; set; }
}
public class Person { public int PersonId { get; set; } public int SocialSecurityNumber { get; set; } public string FirstName { get; set; } public string LastName { get; set; } public Address Address { get; set; } }

 如果這樣做的話,CodeFirst 使用默認規則,肯定會產生一個單獨的表:Addresses。而我們希望的是 Address中的屬性成為表Person中的字段。這時候,我們需要告訴EF,Address類是個復雜類型,就能解決我們現在遇到的問題。

一、使用默認規則:

使用負責類型默認規則,我們需要遵循三個原則:
1、復雜類型無Key屬性
2、復雜類型只包含原始屬性
3、用作其他類的屬性時,屬性必須是一個單一實例,不能用於集合類型

上例代碼中,我們需要注釋掉 :

//public int AddressId { get; set; }

 然后在Person中增加構造函數: 

public Person()
{
    Address = new Address();
}

 這樣,運行程序的話,Address類就會被認作是 復雜類型了。

二、DataAnnotation 方式:

DataAnnotation 更加簡單 只需要在復雜類型的類上增加屬性標簽[ComplexType]

[ComplexType]
public class Address
{        
    public string StreetAddress { get; set; }
    public string City { get; set; }
    public string State { get; set; }
    public string ZipCode { get; set; }
}

 三、FluntAPI 方式:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    modelBuilder.ComplexType<Address>();
    base.OnModelCreating(modelBuilder);
}

 生成的表結構如下圖:

我們會發現,生成的表結構的字段名稱和類型均是EF默認的,我們當然也可以對其進行配置,我們來用FluntAPI進行配置一下:

 protected override void OnModelCreating(DbModelBuilder modelBuilder)
 {
    //設置Person 類的表名為 t_People
    modelBuilder.Entity<Person>().ToTable("t_People");

    //設置 PersonId 為主鍵且自動增長
    modelBuilder.Entity<Person>().HasKey(p => p.PersonId)
                                 .Property(p => p.PersonId).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);

    //設置Firstname 和 Lastname 的長度為 20
    modelBuilder.Entity<Person>().Property(p => p.FirstName).HasMaxLength(20);
    modelBuilder.Entity<Person>().Property(p => p.LastName).HasMaxLength(20);

    //設置Address 為復雜類型嗎,並設置字段名稱及長度
    modelBuilder.ComplexType<Address>().Property(a => a.City).HasColumnName("City").HasMaxLength(20);
    modelBuilder.ComplexType<Address>().Property(a => a.State).HasColumnName("State").HasMaxLength(20);
    modelBuilder.ComplexType<Address>().Property(a => a.StreetAddress).HasColumnName("Steet").HasMaxLength(30);
    modelBuilder.ComplexType<Address>().Property(a => a.ZipCode).HasColumnName("ZipCode").HasMaxLength(10);

    base.OnModelCreating(modelBuilder);
 }

 生成的表結構如下圖:

四、復雜類型的嵌套

上面已經指出,復雜類型應該只包括原始屬性。但如果在復雜類型中繼續引用一個類會產生什么樣的結果呢?繼續書中的例子:

再創建了兩個新類,PersonalInfo 類 和 Measuremet 類,PersonalInfo 包含有兩個Measurement 屬性。

注意兩個類都沒有標識屬性。我們的意圖是兩個類都成為復雜類型。PersonalInfo復雜類型使用Measurment復雜類型,這就是所謂的嵌套復雜類型。

public class PersonalInfo
{
  public Measurement Weight { get; set; }
  public Measurement Height { get; set; }
  public string DietryRestrictions { get; set; }
}
public class Measurement
{
   public decimal Reading { get; set; }
   public string Units { get; set; }
}

 向Person類中添加新的PersonInfo屬性:

public PersonalInfo Info { get; set; }

 修改Person類的構造函數:

public Person()
{
   Address = new Address();
   Info = new PersonalInfo
   {
    Weight = new Measurement(),
    Height = new Measurement()
   };
} 

 然后,我們去掉先前配置的那些 DataAnnotation 和 FluntAPI,采用默認的配置方式,我們運行一下程序,會出現以下錯誤:

實體類"PersonInfo"沒有定義鍵。請為此實體類定義鍵。

Code First 並沒有將PersonalInfo識雖為復雜類型。原因是打破了規則:復雜類型必須只包含原生類型。在PersonalInfo類中有兩個Measurement類型的屬性。由於這是非原生類型,規則不能將PersonalInfo作為復雜類型

解決方法:對PersonalInfo 類 配置 [ComplexType] 屬性,就能夠將屬性建立到表中,不需要配置配置Measurement類,因為它遵循復雜類的規則。

 --=本文源碼=--


免責聲明!

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



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