如何在EF中解决此循环依赖关系

时间:2013-10-13 09:55:48

标签: asp.net-mvc entity-framework ef-code-first entity-framework-5 circular-dependency

在我的申请中,Agency有许多Employees,其中一个被委派给代理机构的所有者:

public class Employee
{
    public int EmployeeId { get; set; }
    public string EmployeeName { get; set; }
    public int EmployerId { get; set; }

    [ForeignKey("EmployerId")]
    public virtual Agency Employer { get; set; }
}

public class Agency
{
    public int AgencyId { get; set; }
    public string AgencyName { get; set; }
    public int OwnerId { get; set; }

    [ForeignKey("OwnerId")]
    public virtual Employee Owner { get; set; }

    [InverseProperty("Employer")]
    public virtual ICollection<Employee> Employees { get; set; }
}

我尝试使用以下代码在数据库中输入新的Agency

var agency = new Agency();
// ... 

context.Agencies.Add(agency);

var owner = new Employee();
// ...

context.Employees.Add(owner);

owner.Employer = agency;
agency.Owner = owner;

context.SaveChanges();

当我调用SaveChanges时,我收到以下错误,我认为是由于上面描述的循环依赖:

  

无法确定相关操作的有效排序。   由于外键约束,模型可能存在依赖关系   要求或商店生成的值。

EF中有没有办法指定&#34;依赖操作的顺序&#34;?或者,有没有更好的方法来编写我的数据库,以便解决这个问题,但仍然模拟我想要的数据结构?

1 个答案:

答案 0 :(得分:3)

我不确定是否可以在SQL中创建代理商和所有者,因为要向代理商存储您需要有效FK的代理商,并且需要向代理商存储您需要有效FK的所有者。由于FK约束(除非它们不会被强制执行),否则不能在不违反约束的情况下存储任何这些约束。

解决方案(我不知道另一个)正在使其中一个关系成为可选关系,例如OwnerOwnerId定义为可空:

public int? OwnerId { get; set; }

这不会立即解决“有效订购”例外情况,但现在您可以存储没有所有者的代理商,然后将所有者与该已存储代理商的关系存储起来。要使整个操作“原子化”,您可以将对SaveChanges的两个必要调用包装到外部事务中:

using (var tx = new TransactionScope())
{
    var agency = new Agency();

    context.Agencies.Add(agency);

    context.SaveChanges(); // inner transaction 1
    // saves agency with OwnerId = NULL, it wouldn't work with a required owner
    // agency has a primary key from the database now

    var owner = new Employee();

    context.Employees.Add(owner);

    owner.Employer = agency; // sets FK EmployerId to the now known PK of agency
    agency.Owner = owner;

    context.SaveChanges(); // inner transaction 2

    tx.Complete(); // commits the outer transaction
}