2017-09-13 95 views
1

我想映射兩個不同的EF模型到同一個表SharedTable,讓我們稱他們爲EntityA和EntityB。我讓它們都擴展了一個名爲BaseEntity的基本實體。EF繼承與表拆分

EntityA僅與SharedTable字段一起定義,EntityB在SharedTable和EntityBTable中具有字段。

 modelBuilder.Entity<BaseEntity>() 
      .Map<EntityA>(m => m.Requires("IsEntityA").HasValue<bool>(true)) 
      .Map<EntityB>(m => m.Requires("IsEntityA").HasValue<false>(true)); 

     modelBuilder.Configurations.Add(new EntityBMap()); 
     modelBuilder.Configurations.Add(new EntityAMap()); 
     modelBuilder.Configurations.Add(new BaseEntityMap()); 

的模型看起來像這樣

public class BaseEntity 
{ 
    [Required] 
    public int Id { get; set; } 
    public int SharedTableField1 { get; set; } 
} 

public class EntityA : BaseEntity 
{ 
    public int SharedTableField2 { get; set; } 
} 

public class EntityB : BaseEntity 
{ 
    public int EntityBTableField1 { get; set; } 
} 

的映射是

public class BaseEntityMap : EntityTypeConfiguration<BaseEntity> 
{ 
    public BaseEntityMap() 
    { 
     // Primary Key 
     this.HasKey(t => t.Id); 

     this.ToTable("SharedTable"); 
     this.Property(t => t.Id).HasColumnName("Id"); 
     this.Property(t => t.SharedTableField1).HasColumnName("SharedTableField1"); 
    } 
} 

public class EntityAMap : EntityTypeConfiguration<EntityA> 
{ 
    public EntityAMap() 
    { 
     this.HasKey(t => t.Id); 
     this.Property(t => t.Id).HasColumnName("Id"); 
     this.ToTable("SharedTable"); 
     this.Property(t => t.SharedTableField2).HasColumnName("SharedTableField2"); 
    } 
} 

public class EntityBMap : EntityTypeConfiguration<EntityB> 
{ 
    public EntityBMap() 
    { 
     Map(c => 
     { 
      HasKey(t => t.Id); 
      Property(t => t.Id).HasColumnName("Id"); 
      c.Properties(t => new 
      { 
       t.SharedTableField2 
      }); 
      c.ToTable("SharedTable"); 
     }); 

     Map(c => 
     { 
      c.Properties(t => new 
      { 
       t.EntityBTableField1 
      }); 
      c.ToTable("EntityBTable"); 
     }); 
    } 
} 

我得到的錯誤說:

'System.NotSupportedException' 類型的第一次機會異常發生在EntityFramework.dll中

附加信息:類型'EntityB'不能按照定義進行映射,因爲它將繼承的屬性映射到使用實體分割或其他形式的繼承的類型。選擇不同的繼承映射策略,以便不映射繼承的屬性,或者更改層次結構中的所有類型以映射繼承的屬性,並且不使用拆分。

任何方法?

+0

爲什麼要將't.EntityBTableField1'映射到另一個表? (這被稱爲*實體分割*)。 –

+0

將它存儲在另一個表中是有意義的,因爲它不會在所有記錄中使用,因此在不需要獲取時會減少檢索的數據量。 – MaPi

+0

這可能是有意義的,如果它是關於大型對象或實際上昂貴的計算域。我不會擔心幾個int或其他小類型。你也可以使用投影('Select(x => new {...}')來限制查詢結果中的字段數量。 –

回答

0

您選擇的繼承策略是Table per Type (TPT)

您有三種類型:一種基本類型BaseEntity和兩種派生類型EntityAEntityB。你決定把它們分成三個獨立的表格。 EntityAEntityBBaseEntity屬性將被放在一張表中。 EntityAEntityB每個都有BaseEntity表中的基本屬性的外鍵。

這是否繼承策略是最適合你的問題取決於你是否將主要查詢BaseEntities那......還是「EntityA / EntityB`說......請考慮使用Table per concrete class (TPC)

的TPT繼承策略意味着對於每個查詢EntityA的加入,其中...使用基類屬性。如果您使用TPC,則不需要此連接。但是,無論何時您詢問'BaseEntities`,TPC都需要一個Concat ......因此,這取決於您最常做哪種類型的查詢,哪種繼承策略最適合您的需求。

如果你想堅持戰略TPT,似乎你不建立你的模型正確。

  • 你不希望任何人自己存儲BaseEntity對象。如果你允許,它不會是繼承,但一到零或一的關係:每EntityA屬於一個BaseEntity,每BaseEntity有零或一個「EntityA . This is not what you want: every BaseEntity has exactly either one EntityA or one ' EntityB , and every 'EntityA/EntityB只有一個'BaseEntity`
  • 由於您不想存儲BaseEntity對象,所以'BaseEntity`類應該聲明爲抽象的,就像給定的TPT鏈接一樣。
  • EntityA en EntityB的類定義中,請不要提及BaseEntity表的外鍵。另外,請給定鏈路的TPT

我認爲抽象基類和缺乏外鍵是讓實體框架知道你選擇 繼承策略TPT的 關鍵信息。

  • 在你的建築模型,僅在需要的列名提表名和。不要提及外鍵

當我像這樣構建模型時,實體框架像TPT一樣創建了三個表。任何額外的流暢的API或屬性都是需要的。儘管我沒有提到外鍵,實體框架知道它們需要作爲多態關聯。再次看到鏈接到TPT

順便說一下,是你的整數[必需]有用嗎?即使我想,我也不能給這個整數一個空值。你不是這個意思嗎?正如您所遵循entity framework code first conventions即使這不是必要的。