在 EF 中处理循环引用的干净方法?

发布于 2024-12-15 05:32:42 字数 1796 浏览 3 评论 0原文

假设我有这个表结构:

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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

柒七 2024-12-22 05:32:42

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

在这种情况下 - 从领域驱动设计的角度来处理它 - 我会说 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 ClientDemographics.First(cd => cd.IsCurrent); }
    }
}

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 and ClientDemographic is a value object; ClientDemographics are defined by the values of their 'Other ClientDemographic fields'. You can therefore remove ClientId from ClientDemographic, 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 multiple ClientDemographics as well as a CurrentClientDemographic property, you can go the other way; remove CurrentClientDemographicId from Client, and add an IsCurrent binary field to ClientDemographic. The EF then gives you a ClientDemographics collection property, and you can add the following yourself in a new, partial class:

public partial class Client
{
    public ClientDemographic CurrentDemogaphic
    {
        get { return ClientDemographics.First(cd => cd.IsCurrent); }
    }
}
纸短情长 2024-12-22 05:32:42

避免此错误的简单方法是首先创建主对象 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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文