2013-03-24 59 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