我理解为什么 EF 在 PK/FK 关系中不允许“循环引用”。我正在寻找有关如何更改我的模型以使以下场景起作用的建议。

设想

三个实体: EmployeeAgencyWorkRecord 。它们的目的是记录员工花在工作上的时间。 Employee 然后包含对他/她受雇的 Agency 的引用,而他/她的 WorkRecord 包含对完成工作的 Agency 的引用。

public class Employee
{
    [Key]
    public int Id { get; set; }

    public string Name { get; set; }

    public int AgencyId { get; set; }
    public virtual Agency Agency { get; set; }

    public virtual IEnumerable<WorkRecord> WorkRecords { get; set; }
}

public class Agency
{
    [Key]
    public int Id { get; set; }
}

public class WorkRecord
{
    [Key]
    public int Id { get; set; }

    public int Hours { get; set; }

    public int AgencyId { get; set; }
    public virtual Agency Agency { get; set; }

    public int EmployeeId { get; set; }
    public virtual Employee { get; set; }
}

像这样,它婊子:FK_dbo.WorkRecords_dbo.Employees_EmployeeId 导致循环引用。

实验

我的第一个想法是因为双向虚拟属性,所以我决定将两者之一指定为具有单向关系的顶级实体:

首先,我将 WorkRecord 指定为顶级实体,并从 WorkRecords 实体中删除虚拟 Employee 引用引用……产生相同的消息。

其次,我将 Employee 设为顶级实体,保留其虚拟 WorkRecords 集合,并从 Employee 实体中删除虚拟 WorkRecord 引用属性...工作正常,但无法实现我的目标。

经过更多调查,我发现是两个实体上的 Agency 虚拟引用属性导致了循环引用。如果一个实体将其删除,则 Employee/WorkRecord 实体关系将在所有方向上起作用。

问题:

所以,正如我所问的那样 - 我如何表达这种业务模型,使用 WorkRecord 作为我的顶级实体,而不会让 EF5 感到不安?

最佳答案

听起来您只是想摆脱 EF,但我认为它实际上表达了数据耦合中的一个有效问题。例如,如果您将 AgencyId 绑定(bind)到 WorkRecord 和 Employee,那么更新 WorkRecord 上的 AgencyId 将级联到 Employee。然后将级联到 WorkRecord 等。因此“循环引用”。您确实应该指定哪些数据对象将“拥有”与 Agency 的关系。

就个人而言,我怀疑最自然的绑定(bind)是从 WorkRecord 中引用该机构。我可以看到一个场景,员工可能会从一个机构转移到另一个机构,但 WorkRecord 从一个机构转移到另一个机构要困难得多。还有一种情况是,没有 WorkRecord 的 Employee 不能真正被称为 Employee,真的。如果您确定是这种情况,那么我会从 Employee 中删除 Agency 引用。如果您需要从 Employee 到达代理机构,那么您可能无论如何都应该通过 WorkRecord。

然而,所有这些都只是概念上的。我怀疑,如果您使 Employee 上的 AgencyId 可能为空,EF 将不再提示(并且您可能希望它在两者上都是可选的)。这应该使更新员工有效,而无需使用 WorkRecord 进行循环更新。我必须测试它来验证,但我怀疑它会成立。

public class Employee
{
    [Key]
    public int Id { get; set; }

    public string Name { get; set; }

    public int? AgencyId { get; set; }
    public virtual Agency Agency { get; set; }

    public virtual IEnumerable<WorkRecord> WorkRecords { get; set; }
}

10-06 05:38