清洁处理EF中的循环引用的方法?

说我有这个表结构:

Client ----------- ClientId int not null (identity) CurrentDemographicId int null (FK to ClientDemographic) OtherClientFields varchar(100) null ClientDemographic ------------------ ClientDemographicId int not null (identity) ClientId int not null (FK to Client) OtherClientDemographicFields varchar(100) null 

我们的想法是Client(在EF中)将具有ClientDemographics列表和CurrentDemographic属性。

问题是当我设置对象结构并尝试保存它时,我收到此错误:

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

这个错误是有道理的。 我在表格设置中有一个循环引用。 它不知道首先插入哪个实体(因为它同时需要来自两个表的Id)。

所以,我一起攻击了一个看起来像这样的解决方案:

 // Save off the unchanged ClientDemograpic ClientDemographic originalClientDemographic = client.CurrentClientDemographic; // Merge the contract into the client object Mapper.Map(contract, client); // If this is a new client then add as new to the list. if (client.ClientId == 0) { dataAccess.Add(client); } // Restore the original ClientDemographic so that EF will not choke // on the circular reference. ClientDemographic newClientDemographic = null; if (client.CurrentClientDemographic != originalClientDemographic) { newCurrentClientDemographic = client.CurrentClientDemographic; client.CurrentClientDemographic = originalClientDemographic; } // save our changes to the db. dataAccess.SaveChanges(); // Restore updates to ClientDemographics and save (if needed) if (newClientDemographic != null) { client.CurrentClientDemographic = newCurrentClientDemographic; dataAccess.SaveChanges(); } 

但是将参考值更改回以前的值,保存,然后再次设置,以便我可以再次保存,感觉就像一个黑客。

有没有更简洁的方法来处理EF中的循环引用?

我会说答案是:“不是真的”。 处理循环引用的唯一简洁方法是再次查看设计并将其删除。

在这种情况下 – 从Domain Driven Design的角度来看它 – 我会说Client是你聚合的根, ClientDemographic是一个值对象; ClientDemographics由其“其他ClientDemographic字段”的值定义。 因此,您可以从ClientDemographic删除ClientId ,并且可以防止问题而不是解决问题。

也就是说,如果你已经确定了这个结构,那么不幸的是我认为在EF中没有一种巧妙的处理方式,没有。

编辑 :要为Client多个ClientDemographics以及CurrentClientDemographic属性,您可以采用其他方式; 从Client删除CurrentClientDemographicId ,并将IsCurrent二进制字段添加到ClientDemographic 。 然后,EF会为您提供ClientDemographics集合属性,您可以在新的部分类中添加以下内容:

 public partial class Client { public ClientDemographic CurrentDemogaphic { get { return this.ClientDemographics.First(cd => cd.IsPrimary); } } } 

避免此错误的简单方法是首先创建主对象,SaveChanges然后再次调用SaveChanges之前创建依赖对象。

在这种情况下,首先创建Client,SaveChanges,然后创建ClientDemographic对象,将其添加到集合并将其设置为CurrentDemographic,然后再次设置SaveChanges。