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

Vac*_*ano 17 c# entity-framework circular-dependency entity-framework-4

说我有这个表结构:

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
Run Code Online (Sandbox Code Playgroud)

我们的想法是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();
}
Run Code Online (Sandbox Code Playgroud)

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

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

Ste*_*kes 15

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

在这种情况下 - 从Domain Driven Design的角度来看它 - 我会说这Client是你的聚合的根,它ClientDemographic是一个值对象; ClientDemographics由他们的"其他ClientDemographic字段"的值定义.因此,您可以删除ClientIdClientDemographic,并且防止了问题,而不是治愈.

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

编辑:为了给ClientClientDemographics还有一个CurrentClientDemographic属性,你可以走另外一条道路; CurrentClientDemographicId从中删除Client,并添加IsCurrent二进制字段ClientDemographic.然后,EF会为您提供一个ClientDemographics集合属性,您可以在一个新的分部类中添加以下内容:

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

  • 不客气:)正如我在[这个问题]的回答中提到的(http://stackoverflow.com/questions/6834085/returning-datasets-from-linq-to-sql-in-a-rest-wcf- service/6834897#6834897),我建议不要将域模型对象与 WCF 混合。相反,我将创建一个专门针对您的 WCF 需求定制的单独的数据传输对象层,并在它们和您的 EF 对象之间进行映射。您的 DTO 可以具有循环依赖关系,并且 EF 不需要知道它:) (2认同)