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

时间:2011-11-11 22:09:08

标签: c# entity-framework entity-framework-4 circular-dependency

说我有这个表结构:

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中的循环引用?

2 个答案:

答案 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。