Come modellare correttamente l'aggregazione rispetto alla persistenza?

3

Quando modellate entità di dominio più grandi avrete probabilmente un qualche tipo di relazione tra queste entità. Queste relazioni di solito si traducono in entità che fanno riferimento a entità diverse. Se non sbaglio, ci sono due modi per modellare queste relazioni:

  • Aggregazione (A utilizza B)
  • Composizione (A possiede B)

Durante la modellazione di Composizione, l'entità radice gestisce la durata delle sue entità composte. Ciò vale anche per la persistenza, in cui è necessario ripulire le entità composte, quando l'entità root viene cancellata.

Ciò di cui sto avendo problemi è lo stesso scenario, usando semplicemente Aggregation. Come modellate la relazione tra entità, quando possono esistere indipendentemente e la stessa entità può essere aggregata da più entità radice? Ciò diventa ancora più complicato quando si suppone che entrambe le entità siano salvate in un database.

Adottare questi requisiti, ad esempio:

We want to model recipes, which consist of different ingredients and their quantities. Recipes and ingredients can be provided with additional information, like descriptions, pictures and user comments. Ingredients can also be provided with links to substitute ingredients and recipes to make the ingredients (bread can be made using a recipe for example).

Vorrei iniziare separando le diverse entità di dominio, specificate dai requisiti e aggiungendo i campi di proprietà delle entità (composizione). Sarebbero informazioni come commenti, immagini e descrizioni. Ma non so come modellare correttamente l'aggregazione tra le entità, in modo che la gestione indipendente abbia senso e posso facilmente integrarla nel mio Data Access Layer (database).

Potresti fornirmi un esempio di codice breve che dimostra come dovrei modellare la relazione tra Recipe e Ingredient , in modo che io possa usarlo facilmente nella mia applicazione e non abbia un incubo nel mio codice di persistenza ? Usa la tua lingua preferita!

    
posta Luca Fülbier 03.07.2016 - 18:58
fonte

2 risposte

3

Commento preliminare

Ho la sensazione che un concetto importante sia ancora nascosto negli "ingredienti" nella tua richiesta. Perché c'è:

  • l'ingrediente in generale (ad esempio zucchero, mela, uovo), con l'immagine e informazioni indipendenti dalla ricetta;
  • l'uso di un ingrediente in una ricetta (ad esempio 20 g di zucchero, 1 kg di mele).

A proposito, penserei che l'ingrediente sostitutivo sia legato all'uso in una ricetta (ad esempio puoi sostituire lo zucchero con il miele quando fai una crostata, ma mia madre usa per mettere un pizzico di zucchero nell'insalata di carote e non sono sicuro che nonay potrebbe farlo qui).

In questo caso è meglio modellare questa situazione con una classe di associazione:

Composizione

ConcentriamocisullarelazionetraRecipeeIngredientUseedimenticala%grezzaIngredient.

Questaèchiaramenteunarelazionedicomposizione:ilIngredientUsehasolounsensoall'internodiRecipe.Nessunaricetta,nessunusodiingredienti.Questaèchiaramenteunaproprietàesclusiva.

InC++implementereiquestarelazionecomeproprietàcompleta:laIngredientUsesarebbecontenutainunvettoreinRecipe.QuandoRecipevienedistrutto,vecotreilsuocontenutovengonodistrutticonesso:

classIngredientUse{...};classRecipe{protected:vector<IngredientUse>ingredients;...};

Sololaricettapuòaccedereaisuoiingredientiusati.Gliingredientipotrebberoessereidentificatidalloroindicenelvettore.

Un'altravariantesarebbeavereunelencodiindicatori.Mainquestocasoutilizzereiunpuntatoreintelligentecheesprimaadeguatamentelaproprietà:

classRecipe{protected:list<unique_ptr<IngredientUse>>ingredient_pointers;//ownershipclearlyexpressedincode...};

Quandolaricettavienedistrutta,loèanchel'elenco,eunique_ptrsiassicureràcheanchel'oggettodiproprietàvengacancellato.

Inundatabaserelazionale,utilizzereiunIDunivoco,adesempioID-RECIPEcomechiaveprimariaperRecipe.MaperIngredientUse,invecediusareunIDunivoco,usereiunachiaveprimariacompostadaunachiaveID-RECIPEdifronteeunnumerosequenzialeinRecipe:

  • Laproprietàvienequindiespressainmodochiaro(adesempio,lachiaveprimariahasensosoloinsiemeallaRicettaproprietaria).
  • RDBMScheabilitanoadichiarare integrità referenziale i vincoli possono eventi prendersi cura di cancella in cascata .

Agrégation

L'aggregazione è diversa, perché è una proprietà condivisa . Immagina che la tua applicazione non riguardi più la composizione esatta di una ricetta, ma solo gli ingredienti generici, al fine di prevenire le allergie, o contribuire a fare delle scelte in base ai gusti preferiti.

In questo caso la relazione tra Recipe e Ingredient non sarebbe una composizione: un Recipe potrebbe scomparire, ma il generico Ingredients verrebbe comunque utilizzato da altre ricette.

In questo caso nel mio codice C ++, non potrei più tenere gli ingredienti in base al valore nella mia ricetta. Avrei bisogno di avere una proprietà condivisa. Ad esempio:

class Recipe {
protected: 
    vector< shared_ptr<Ingredient> > ingredient_pointers;  //shared ownership obvious
...
};

Quindi gli elementi aggregati non possono essere memorizzati all'interno dell'oggetto di attesa. Devono essere conservati in un modo per essere potenzialmente riutilizzati. Il puntatore intelligente che ho usato sopra esprime proprietà condivisa. L'ingrediente è tenuto in vita fino a quando nessuna ricetta lo usa più.

Nel modello di database, Ricetta e Ingrediente avrebbero entrambi ID univoci nella rispettiva tabella (ad esempio ID-RECIPE e ID-INGREDIENT ). Per rappresentare l'associazione, aggiungerei quindi una tabella INGREDIENTS-IN-RECIPE che contiene le combinazioni pertinenti di ID-RECIPE e ID-INGREDIENT . L'integrità referenziale e l'eliminazione a cascata eliminerebbero quindi solo i record di associazione per le ricette eliminate, senza mai eliminare l'ingrediente principale.

    
risposta data 03.07.2016 - 23:09
fonte
1

Penso che questo dipenda dal fatto che la tua ricetta abbia

List<string> IngredientIds

o

List<Ingredient> Ingredients

Con il primo devi recuperare gli ingredienti separatamente dal tuo livello di persistenza. Pehaps usando un repository diverso per la ricetta

Con quest'ultimo, gli ingredienti e la ricetta vengono mantenuti quando la ricetta viene salvata

    
risposta data 03.07.2016 - 19:09
fonte

Leggi altre domande sui tag