我有一个我正在定义的几个实体的抽象基类。其中一个派生实体实际上是另一个实体的非抽象基类。
遵循以下代码:
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");
});
}
}
如果需要,这是ReportBundle类
public class ReportsBundle
{
public int ReportsBundleId { get; set; }
public virtual ICollection<PerformanceReportEntry> PerformanceReportEntries{ get; set; }
public virtual ICollection<ByPeriodPerformanceReportEntry> ByPeriodPerformanceReportEntries{ get; set; }
}
答案 0 :(得分:2)
问题不在于第二级继承,而是PerformanceReportEntry
(ByPeriodPerformanceReportEntry
的基础)是一个实体而BaseReportEntry
(PerformanceReportEntry
的基础)不是。
如果PerformanceReportEntry
不是实体,您的映射将起作用 - 即它的映射未添加到模型构建器配置中,并且此类型没有DbSet
,并且它不会出现在导航中ReportsBundle
中的集合。
在这种情况下无法从BaseReportEntryMap<ByPeriodPerformanceReportEntry>
派生配置 - 并且没有必要,因为基本属性的映射已经由BaseReportEntryMap<PerformanceReportEntry>
发生。因此,您可以使用
public class ByPeriodPerformanceReportEntryMap
: EntityTypeConfiguration<ByPeriodPerformanceReportEntry>
但我怀疑所得到的模型是否符合您的预期。我不知道PerformanceReportEntries
中的ByPeriodPerformanceReportEntries
和ReportsBundle
个集合应该表达什么。您是否期望ByPeriodPerformanceReportEntries
是由子类型过滤的集合?您是否希望PerformanceReportEntries
仅包含PerformanceReportEntry
但不包含ByPeriodPerformanceReportEntry
s的ReportsEntries?您是否希望PerformanceReportEntries
包含所有条目,包括ByPeriodPerformanceReportEntries
?
无论如何,BaseReportEntry.ReportBundle
是映射在PerformanceReportEntry
(不在ByPeriodPerformanceReportEntry
中)的导航属性。这意味着类ReportsBundle
中的反向导航属性必须引用PerformanceReportEntry
这是PerformanceReportEntries
导航集合。 ByPeriodPerformanceReportEntries
将在ReportsBundle
和ByPeriodPerformanceReportEntry
之间引入第二个一对多关系(ByPeriodPerformanceReportEntry
中没有导航属性)。 ByPeriodPerformanceReportEntries
的反向导航属性不会是BaseReportEntry.ReportBundle
。
我的感觉是你不应该拥有ReportsBundle.ByPeriodPerformanceReportEntries
集合,但我不确定你想要达到什么目的。
修改强>
根据您的评论,您只有这两种报告类型,我认为您的映射过于复杂。我会做以下事情:
删除BaseReportEntry
类并将其属性移至PerformanceReportEntry
。拥有一个只有一个其他类派生自己的基类是没有意义的。
从ByPeriodPerformanceReportEntries
移除ReportsBundle
,以便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);
}
}
从ByPeriodPerformanceReportEntryMap
派生EntityTypeConfiguration<ByPeriodPerformanceReportEntry>
并仅指定ByPeriodPerformanceReportEntry
中声明的属性的映射,而不是基本属性的映射。那已经发生在PerformanceReportEntryMap
。您不需要也不能再次指定它,因为它会导致您的例外。
使用Table-Per-Layer(TPH)继承而不是Table-Per-Concrete-Type(TPC),特别是如果您只在ByPeriodPerformanceReportEntry
中声明了一些属性。 TPC更难以使用,因为它在数据库生成的身份和多态关联方面存在问题(您在PerformanceReportEntry
和ReportsBundle
之间的关系中存在这种关联)。 The problems are explained in more details here。相反,TPH提供最佳性能。 ByPeriodPerformanceReportEntryMap
将如下所示:
public class ByPeriodPerformanceReportEntryMap
: EntityTypeConfiguration<ByPeriodPerformanceReportEntry>
{
public ByPeriodPerformanceReportEntryMap()
{
this.Property(e => e.Period).IsRequired();
}
}
没有必要对TPH进行显式配置,因为它是默认的继承映射。