在 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
这个想法是客户端(在 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 中的循环引用?
Say I have this table structure:
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
The idea is that Client (in EF) will have a ClientDemographics list and a CurrentDemographic property.
The problem is when I setup the object structure and try to save it, I get this error:
Unable to determine a valid ordering for dependent operations. Dependencies may exist due to foreign key constraints, model requirements, or store-generated values
This error makes sense. I have a circular reference in my table setup. It does not know which entity to insert first (because it needs the Id from both tables at the same time).
So, I hacked together a solution that looks like this:
// 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();
}
But changing the reference back to the previous value, saving, then setting it again so I can save again feels like a hack.
Is there a cleaner way to deal with circular references in EF?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我想说的答案是:“不是真的”。处理循环引用的唯一干净方法是再次查看设计并将其删除。
在这种情况下 - 从领域驱动设计的角度来处理它 - 我会说
Client
是聚合的根,而ClientDemographic
是一个值对象;ClientDemographics
由其“其他 ClientDemographic 字段”的值定义。因此,您可以从ClientDemographic
中删除ClientId
,这样问题就可以得到预防而不是解决。也就是说,如果您确定了这种结构,那么不幸的是,我认为 EF 中没有一种巧妙的方法来处理它,没有。
编辑:要为
Client
提供多个ClientDemographics
以及CurrentClientDemographic
属性,您可以采用另一种方式;从Client
中删除CurrentClientDemographicId
,并将IsCurrent
二进制字段添加到ClientDemographic
。然后,EF 为您提供一个ClientDemographics
集合属性,您可以自己在新的分部类中添加以下内容:I'd say the answer is: "not really". The only clean way to deal with the circular reference is to look again at the design and remove it.
In this case - approaching it from a Domain Driven Design perspective - I'd say that
Client
is the root of your aggregate andClientDemographic
is a value object;ClientDemographics
are defined by the values of their 'Other ClientDemographic fields'. You can therefore removeClientId
fromClientDemographic
, and the problem is prevented instead of cured.That said, if you're settled on this structure then unfortunately I don't think there's a neat way of handling it in EF, no.
Edit: To give
Client
multipleClientDemographics
as well as aCurrentClientDemographic
property, you can go the other way; removeCurrentClientDemographicId
fromClient
, and add anIsCurrent
binary field toClientDemographic
. The EF then gives you aClientDemographics
collection property, and you can add the following yourself in a new, partial class:避免此错误的简单方法是首先创建主对象 SaveChanges,然后在再次调用 SaveChanges 之前创建依赖对象。
在本例中,首先创建 Client、SaveChanges,然后创建 ClientDemographic 对象,将其添加到集合中并将其设置为 CurrentDemographic,然后再次 SaveChanges。
The simple way of avoiding this error is to create your primary object first, SaveChanges and then create your dependant object before calling SaveChanges again.
In this case create the Client first, SaveChanges, then create the ClientDemographic object, add it to the collection and set it as the CurrentDemographic and then SaveChanges again.