2013-03-24 83 views
2

我有一個抽象基類,用於我定義的幾個實體。其中一個派生實體實際上是另一個實體的非抽象基類。EF代碼優先配置中的多級繼承

下面這段代碼:

public abstract class BaseReportEntry { 
     public int ReportEntryId { get; set;} 
     public int ReportBundleId { get; set; } //FK 
     public virtual ReportBundle ReportBunde { get; set; } 
} 

//A few different simple pocos like this one 
public PerformanceReportEntry : BaseReportEntry { 
    public int PerformanceAbsolute { get; set; } 
    public double PerformanceRelative { get; set; } 

} 

//And one with a second level of inheritance 
public ByPeriodPerformanceReportEntry : PerformanceReportEntry { 
     public string Period { get; set; } 
} 

我使用的是基礎EntityTypeConfiguration

public class BaseReportEntryMap<TReportEntry> : EntityTypeConfiguration<TReportEntry> 
    where TReportEntry : BaseReportEntry 
{ 
    public BaseReportEntryMap() 
    { 
     this.HasKey(e => e.ReportEntryId); 

     this.HasRequired(e => e.ReportsBundle) 
      .WithMany() 
      .HasForeignKey(e => e.ReportsBundleId); 
    } 
} 

想必這工作得很好繼承的一個層次,但引發以下錯誤的一個案例它有第二級別:

The foreign key component 'ReportsBundleId' is not a declared property on type 'ByPeriodPerformanceReportEntry' 


public class ByPeriodPerformanceReportEntryMap : BaseReportEntryMap<ByPeriodPerformanceReportEntry> 
{ 
    public ByPeriodPerformanceReportEntryMap() 
     : base() 
    { 
     this.Property(e => e.Period).IsRequired(); 

     this.Map(m => 
     { 
      m.MapInheritedProperties(); 
      m.ToTable("ByPeriodPerformanceReportEntries"); 
     }); 
    } 
} 

Here's ReportB ReportB如果需要的話

public class ReportsBundle 
{ 
    public int ReportsBundleId { get; set; } 
    public virtual ICollection<PerformanceReportEntry> PerformanceReportEntries{ get; set; } 
    public virtual ICollection<ByPeriodPerformanceReportEntry> ByPeriodPerformanceReportEntries{ get; set; } 
} 

回答

2

undle類的問題是沒有這麼多繼承的第二電平但PerformanceReportEntry(的ByPeriodPerformanceReportEntry鹼)是一個實體,而BaseReportEntry(的PerformanceReportEntry基)不是。如果PerformanceReportEntry不會是一個實體

你的映射會工作 - 即它的映射不會被添加到模型構建器配置,你有沒有DbSet這種類型和ReportsBundle它不會在導航集出現。

在這種情況下從BaseReportEntryMap<ByPeriodPerformanceReportEntry>導出配置是不可能的 - 因爲基本屬性的映射已經發生在BaseReportEntryMap<PerformanceReportEntry>之內,所以這不是必需的。因此,你可以使用

public class ByPeriodPerformanceReportEntryMap 
    : EntityTypeConfiguration<ByPeriodPerformanceReportEntry> 

但我懷疑得到的模型是你所期望的。我不知道ReportsBundle中的PerformanceReportEntriesByPeriodPerformanceReportEntries集合應該表達什麼。你期望ByPeriodPerformanceReportEntries是一個由子類型過濾的集合嗎?您是否期望PerformanceReportEntries僅包含s的ReportEntries,但不包含ByPeriodPerformanceReportEntry s?你期望PerformanceReportEntries包含所有條目,包括ByPeriodPerformanceReportEntries

無論如何,BaseReportEntry.ReportBundle是映射到PerformanceReportEntry(不在ByPeriodPerformanceReportEntry中)的導航屬性。這意味着類ReportsBundle中的逆導航屬性必須參考PerformanceReportEntry,這是PerformanceReportEntries導航集合。 ByPeriodPerformanceReportEntries將在ReportsBundleByPeriodPerformanceReportEntry(在ByPeriodPerformanceReportEntry中沒有導航屬性)之間引入第二個一對多關係。 ByPeriodPerformanceReportEntries的逆導航屬性將不是BaseReportEntry.ReportBundle

我的感覺是,你不應該有ReportsBundle.ByPeriodPerformanceReportEntries集合,但我不確定你想要達到什麼樣的效果。

編輯

關於你的評論,你只有這兩個報告類型的映射在我看來太複雜。我會做到以下幾點:

  • 取出BaseReportEntry類和移動它的屬性爲PerformanceReportEntry。擁有隻有一個其他類來自的基類是沒有意義的。

  • ByPeriodPerformanceReportEntriesReportsBundle刪除,使得ReportsBundle將是:

    public class ReportsBundle 
    { 
        public int ReportsBundleId { get; set; } 
        public virtual ICollection<PerformanceReportEntry> 
         PerformanceReportEntries { get; set; } 
    } 
    
  • 卸下BaseReportEntryMap並移動映射進PerformanceReportEntryMap。從EntityTypeConfiguration<PerformanceReportEntry>導出此地圖。

  • 更正映射。目前它是錯誤的,因爲您沒有在WithMany中指定逆導航屬性。 PerformanceReportEntryMap應該是這樣的:

    public class PerformanceReportEntryMap 
        : EntityTypeConfiguration<PerformanceReportEntry> 
    { 
        public PerformanceReportEntryMap() 
        { 
         this.HasKey(e => e.ReportEntryId); 
    
         this.HasRequired(e => e.ReportsBundle) 
          .WithMany(b => b.PerformanceReportEntries) 
          .HasForeignKey(e => e.ReportsBundleId); 
        } 
    } 
    
  • 派生ByPeriodPerformanceReportEntryMapEntityTypeConfiguration<ByPeriodPerformanceReportEntry>和那些宣佈ByPeriodPerformanceReportEntry,不能再爲基本屬性的屬性指定唯一的映射。這已經發生在PerformanceReportEntryMap。您不需要也不能再指定它,因爲它會導致您的異常。

  • 使用Table-Per-Hierarchy(TPH)繼承來代替Table-Per-Concrete-Type(TPC),特別是如果只有在ByPeriodPerformanceReportEntry中聲明的幾個屬性。 TPC更難以使用,因爲它存在數據庫生成的身份和多態關聯(您在PerformanceReportEntryReportsBundle之間的關係中存在問題)。 The problems are explained in more details here。 TPH改爲提供最佳性能。然後ByPeriodPerformanceReportEntryMap應該是這樣的:

    public class ByPeriodPerformanceReportEntryMap 
        : EntityTypeConfiguration<ByPeriodPerformanceReportEntry> 
    { 
        public ByPeriodPerformanceReportEntryMap() 
        { 
         this.Property(e => e.Period).IsRequired(); 
        } 
    } 
    

    的TPH沒有明確的配置是必要的,因爲它是默認繼承映射。

+0

感謝您的回覆,並對缺乏清晰度感到抱歉。基本上,我正在模擬一個外部報告系統,它具有這兩個獨立的報告。我打算使用ByPeriodPerformanceReportEntry和PerformanceReportEntry作爲單獨的具體實體,它們基本上只有公共屬性(PerformanceAbsolute,PerformanceAbsolute等等)。您認爲您可以使用這些新信息更新您的代碼嗎?謝謝你的幫助 – parliament 2013-03-25 01:17:24

+0

我想你的意思是讓PerformanceReportEntry抽象,併爲具體實現創建第三個類,如「ConsolidatedPerformanceReportEntry」。這會工作嗎?這是最好的選擇嗎? – parliament 2013-03-25 01:19:05

+1

@Vazgen:我在我的答案中添加了編輯部分。 – Slauma 2013-03-25 18:01:55