Vraag Schone manier om met cirkelverwijzingen in EF om te gaan?


Stel dat ik deze tabelstructuur heb:

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

Het idee is dat Client (in EF) een ClientDemographics-lijst en een CurrentDemographic-eigenschap zal hebben.

Het probleem is wanneer ik de objectstructuur installeer en probeer het op te slaan, krijg ik de volgende foutmelding:

Kan geen geldige volgorde bepalen voor afhankelijke bewerkingen. Er kunnen afhankelijkheden zijn vanwege externe sleutelbeperkingen, modelvereisten of door winkel gegenereerde waarden

Deze fout is logisch. Ik heb een circulaire referentie in mijn tabelopstelling. Het weet niet welke entiteit het eerst moet worden ingevoegd (omdat het de ID van beide tabellen op hetzelfde moment nodig heeft).

Dus ik heb een oplossing gehacked die er zo uitziet:

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

Maar de referentie terugzetten naar de vorige waarde, opslaan en vervolgens opnieuw instellen, zodat ik weer kan opslaan, voelt als een hack.

Is er een schonere manier om met cirkelverwijzingen in EF om te gaan?


15
2017-11-11 22:09


oorsprong


antwoorden:


Ik zou zeggen dat het antwoord is: "niet echt". De enige schone manier om met de kringverwijzing om te gaan, is door opnieuw naar het ontwerp te kijken en het te verwijderen.

In dit geval - het benaderen vanuit het perspectief van Domain Driven Design - zou ik dat zeggen Client is de hoofdmap van uw verzameling en ClientDemographic is een waardeobject; ClientDemographics worden gedefinieerd door de waarden van hun 'Andere ClientDemografische velden'. U kunt daarom verwijderen ClientId van ClientDemographicen het probleem wordt voorkomen in plaats van genezen.

Dat gezegd hebbende, als je genoegen neemt met deze structuur dan denk ik helaas niet dat er een nette manier is om het in EF te behandelen, nee.

Bewerk: Geven Client meerdere ClientDemographics evenals een CurrentClientDemographic eigendom, je kunt de andere kant op; verwijderen CurrentClientDemographicId van Clienten voeg een toe IsCurrent binair veld naar ClientDemographic. De EF geeft je dan een ClientDemographics collectie-eigenschap, en u kunt het volgende zelf toevoegen in een nieuwe, gedeeltelijke klasse:

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

13
2017-11-11 23:04



De eenvoudige manier om deze fout te vermijden, is eerst uw primaire object aan te maken, SaveChanges en vervolgens uw afhankelijke object te maken voordat u SaveChanges opnieuw belt.

Maak in dit geval eerst de Client, SaveChanges, maak vervolgens het ClientDemographic-object, voeg het toe aan de verzameling en stel het opnieuw in als CurrentDemographic en dan SaveChanges.


2
2018-01-04 16:54