Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
146 views
in Technique[技术] by (71.8m points)

c# - Clean way to deal with circular references in 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?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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); }
    }
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...