0

我有一个 EF 数据模型,它表示具有报告部分的层次结构树的报告。每个 ReportSection 实体包含零个或多个子 ReportSection 的集合。每个 Report 实体包含一个 ReportSection 实体,用作 ReportSection 树的根。

我的数据模型具有以下导航属性:

public class Report
{
    // Primary key
    public int Id { get; set; }

    // A Report has one root ReportSection
    [ForeignKey("RootReportSection")]
    public int ReportSectionId { get; set; }
    public virtual ReportSection RootReportSection { get; set; }
}

public class ReportSection
{
    // Primary key
    public int Id { get; set; }

    // Optional self-reference to the parent ReportSection
    [ForeignKey("ParentReportSection")]
    public int? ParentReportSectionId { get; set; }
    public virtual ReportSection ParentReportSection { get; set; }

    // Optional foreign key to the parent Report
    [ForeignKey("ParentReport")]
    public int? ReportId { get; set; }
    public virtual Report ParentReport { get; set; }

    // Child ReportSections contained in this ReportSection
    public virtual ICollection<ReportSection> ReportSections { get; set; }
}

如果我从报告实体中省略ReportSectionIdRootReportSection导航拍手,一切正常。但是,如上所述,尝试添加迁移会出错:

Because the Dependent Role properties are not the key properties,
the upper bound of the multiplicity of the Dependent Role must be '*'.

经过一番挖掘,我现在明白 EF 显然希望我使用 ReportSections 实体的主键作为我的 Report 实体的外键。但是,在我的场景中,只有 ReportSection 实体的层次结构树中的顶级 ReportSection 参与与 Report 实体的关系。其余的 ReportSection 实体相互关联,它们的主键独立于任何 Report 主键。

有没有办法让它工作?具体来说,有没有办法让 Report 实体“包含”顶级 ReportSection 实体,哪个 ReportSection 实体有自己的自引用 ReportSection 实体集合?

4

1 回答 1

1

显然ReportSection是关系中的主体和Report依赖关系(因为Report必须引用现有的RootReportSection,因为Report.ReportSectionId不可为空)。在这种情况下,很可能ReportSection存在 a 而没有相关的Report。你所有的孩子ReportSection都没有Report

但这只有在 key inReport不是自动生成的情况下才有效,因为 key 必须与相关(并且已经存在)的 key 相同RootReportSection。因此,您可以尝试像这样对其进行建模:

public class Report
{
    [DatabaseGenerated(DatabaseGeneratedOption.None)]
    [ForeignKey("RootReportSection")]
    public int Id { get; set; }

    public virtual ReportSection RootReportSection { get; set; }
}

public class ReportSection
{
    public int Id { get; set; }

    // Optional self-reference to the parent ReportSection
    [ForeignKey("ParentReportSection")]
    public int? ParentReportSectionId { get; set; }
    public virtual ReportSection ParentReportSection { get; set; }

    // Optional foreign key to the parent Report
    public virtual Report ParentReport { get; set; }

    // Child ReportSections contained in this ReportSection
    public virtual ICollection<ReportSection> ReportSections { get; set; }
}

(这可能[DatabaseGenerated(DatabaseGeneratedOption.None)]是多余的,因为 EF 知道密钥不能在这种一对一关系中由数据库生成。不过我不是 100% 确定。)

这种与共享主键的一对一关系的缺点是您无法更改 and 之间的关系Report,即除了具有相同主键的部分之外RootReportSection,您不能引用任何其他部分。Report

如果这对您不起作用,则必须将关系建模为一对多,因为 EF 不支持具有单独外键的一对一关系。要么完全删除那部分......

[ForeignKey("ParentReport")]
public int? ReportId { get; set; }
public virtual Report ParentReport { get; set; }

...如果您不需要从该部分导航到报告或将其替换为集合:

public virtual ICollection<Report> ParentReports { get; set; }

您必须在业务逻辑中确保向此集合添加的报表不超过一个,以模拟一对一的关系。在数据库中,您可以添加唯一约束Report.ReportSectionId以在数据库级别具有数据完整性。但是 EF 不会理解这个约束,仍然允许向集合中添加多个项目。但是,如果您尝试保存它,您会从数据库中获得唯一的密钥违规异常。

于 2013-07-19T16:58:35.617 回答