在EF中处理循环引用的清洁方式? [英] Clean way to deal with circular references in EF?

查看:151
本文介绍了在EF中处理循环引用的清洁方式?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

说我有这个表结构:

 客户
-----------
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)。



所以,我把一个看起来像这样的解决方案:

  //保存未更改的ClientDemograpic 
ClientDemographic originalClientDemographic = client.CurrentClientDemographic;

//将合同合并到客户端对象
Mapper.Map(contract,client);

//如果这是一个新的客户端,然后添加为新列表。
if(client.ClientId == 0)
{
dataAccess.Add(client);
}

//恢复原始ClientDemographic,以便EF不会在循环引用上阻止
//。
ClientDemographic newClientDemographic = null;
if(client.CurrentClientDemographic!= originalClientDemographic)
{
newCurrentClientDemographic = client.CurrentClientDemographic;
client.CurrentClientDemographic = originalClientDemographic;
}

//将我们的更改保存到db。
dataAccess.SaveChanges();

//将更新更新到ClientDemographics并保存(如果需要)
if(newClientDemographic!= null)
{
client.CurrentClientDemographic = newCurrentClientDemographic;
dataAccess.SaveChanges();
}

但将参考更改为上一个值,保存,然后再次设置所以我可以再次保存感觉像一个黑客。



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

解决方案

我会说答案是:不是真的。处理循环引用的唯一干净的方法是重新设计并删除它。



在这种情况下 - 从域驱动设计的角度来看 - 我'd说客户端是您的聚合的根, ClientDemographic 是一个值对象; ClientDemographics 由其他ClientDemographic字段的值定义。因此,您可以从 ClientDemographic 中删除​​ ClientId ,并且阻止该问题而不是治愈。



那就是说,如果你在这个结构上安定下来,不幸的是我不认为在EF中没有一个整洁的方法来处理这个问题,而不是。



编辑:要给客户端多个 ClientDemographics 以及 CurrentClientDemographic 属性,你可以走另一种方式;从客户端中删除​​ CurrentClientDemographicId ,并添加一个 IsCurrent 二进制字段至 ClientDemographic 。 EF然后为您提供一个 ClientDemographics collection属性,您可以将自己添加到新的部分类中:

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


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?

解决方案

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 this.ClientDemographics.First(cd => cd.IsPrimary); }
    }
}

这篇关于在EF中处理循环引用的清洁方式?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆