说我有这个表结构:
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
我们的想法是客户(在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中的循环引用?
答案 0 :(得分:14)
我会说答案是:“不是真的”。处理循环引用的唯一简洁方法是再次查看设计并将其删除。
在这种情况下 - 从域驱动设计的角度来看它 - 我会说Client
是聚合的根,而ClientDemographic
是一个值对象; ClientDemographics
由“其他ClientDemographic字段”的值定义。因此,您可以从ClientId
删除ClientDemographic
,并且可以防止问题而不是治愈。
那就是说,如果你已经确定了这个结构,那么不幸的是我认为在EF中没有一种巧妙的处理方法,没有。
修改:要提供Client
多个ClientDemographics
以及CurrentClientDemographic
媒体资源,您可以采取其他方式;从CurrentClientDemographicId
移除Client
,并向IsCurrent
添加ClientDemographic
二进制字段。然后,EF会为您提供一个ClientDemographics
集合属性,您可以在一个新的部分类中添加以下内容:
public partial class Client
{
public ClientDemographic CurrentDemogaphic
{
get { return this.ClientDemographics.First(cd => cd.IsPrimary); }
}
}
答案 1 :(得分:1)
避免此错误的简单方法是首先创建主对象,SaveChanges然后再次调用SaveChanges之前创建依赖对象。
在这种情况下,首先创建Client,SaveChanges,然后创建ClientDemographic对象,将其添加到集合中并将其设置为CurrentDemographic,然后再次设置SaveChanges。