Relazioni inverse per Aggregati più piccoli / migliori?

3

Facciamo un esempio: abbiamo due entità correlate, come Question e Choice . Questo è un sondaggio : contiene una sola domanda che può avere 2 o più scelte . Ogni scelta può essere votata dagli utenti, ogni voto è memorizzato.

Ovviamente, su carta, Question conterrà una raccolta di Choice s. E probabilmente avremmo qualcosa di simile:

public class Question {
    List<Choice> choices;
    public void assignChoice(Choice choice) {}
    public List<Choice> getChoices();
}

Question è un aggregato che contiene un elenco di altre entità , Choice .

Ora, se Choice è un oggetto valore, starei bene. Il repository dovrebbe memorizzare l'aggregato a partire da root, in modo da memorizzare un'entità root e oggetti valore correlati.

Tuttavia, qui abbiamo aggregato di entità! In questo senso mi chiedo: perché abbiamo bisogno di mantenere la raccolta in questione ? Voglio dire, per la visualizzazione, avremo il modello di sola lettura della query. Per i comandi potremmo non averne affatto bisogno.

Quindi possiamo spostarci da questo:

Question question = new Question("Favorite color?");
question.assignAnswer(new Choice("red"));
question.assignAnswer(new Choice("blue"));

questionRepository.store(question);

a:

Question question = new Question("Favorite color?");
Choice c1 = new Choice(question, "red"); // or just: questionId instead of question?
Choice c2 = new Choice(question, "blue");// the same

questionRepository.store(question);
choiceRepository.store(c1, c2);

Ora non è necessario "assegnare" nulla a Question e non è necessario mantenere la raccolta. Ad esempio, questa collezione può variare - può essere raccolta di scelte appena approvate, o scelte votate, o 3 scelte votate più ecc. Non siamo in grado di esprimere quale tipo di relazione è che solo avendo getChoices() .

Quindi dovremmo andare oltre per avere una regola del tipo:

Don't compose Aggregates with other Entities. Just have a root Entity and value objects. Use reverse relationship to express the connection between aggregate roots.

Ha senso?

    
posta lawpert 31.10.2014 - 18:24
fonte

2 risposte

1

Secondo me, un motivo per lasciare che la domanda sia la radice aggregata delle scelte (e mantenere un elenco di scelte all'interno della domanda) potrebbe essere:

Una scelta non esiste da sola ed è sempre correlata a una domanda specifica (anche come entità). Ecco perché penso che avrebbe senso accedere a una scelta solo attraverso la sua domanda padre.

Un altro vantaggio potrebbe essere che ogni volta che si modifica la domanda, è possibile controllare facilmente tutte le scelte correlate per gli invarianti. Oppure quando elimini la domanda, puoi semplicemente rimuovere tutte le scelte secondarie all'interno dell'operazione Elimina della domanda stessa.

Sono d'accordo sul fatto che tutto questo potrebbe anche essere ottenuto attraverso una relazione inversa, ma a mio parere sarebbe più complicato. Ad esempio, se avessi una relazione inversa e volessi eliminare una domanda, dovrei scorrere tutte le scelte per scegliere quelle correlate a questa domanda specifica.

Per quanto riguarda il tuo punto con le diverse raccolte di scelte all'interno della domanda: Questo è qualcosa in cui potresti aggiungere qualche logica di filtro aggiuntiva e in questo modo implementare alcune regole di dominio all'interno della tua domanda, ad esempio:

public class Question {
List<Choice> choices;
public List<Choice> getHighestVotedChoices();// will query choices and return highest voted choices
public List<Choice> getApprovedVotedChoices(); // will filter choices list "approved property"

}

    
risposta data 01.11.2014 - 00:19
fonte
1

Scelta ha il riferimento alla domanda

Ha senso se si tratta di un composite, vice aggregato .

Analisi dei requisiti inadeguati

Don't compose Aggregates with other Entities. Just have a root Entity and value objects. Use reverse relationship to express the connection between aggregate roots.

Make sense?

No, non è così.

Non è possibile creare tali diktat globali, assoluti. I tuoi requisiti, casi d'uso, informeranno le gerarchie e le relazioni di classe.

it may be collection of just approved choices, or voted choices, or top 3 voted choices etc. We are not able to expressed what kind of relationship is that just by having getChoices()

Sembra che la classe Choice abbia bisogno delle proprietà Approved e Votes . Ora, ottenere le "prime 3 scelte votate" sarebbe abbastanza facile.

Considera: class Choice : IComparable<Choice> quindi puoi Sort() a List<Choice> basato su Votes

I agree that all of this could also be achieved via a reverse relation, but would be more complicated in my opinion. For example, if I would have a reverse relation and want to delete a question, I would have to iterate through all choices to pick the ones that are related to this specific question.

Che cosa succede se una raccolta deve essere ripetuta. Ecco a cosa servono. Il framework .net fa un sacco di problemi per aiutarti a farlo in molti modi.

Inoltre, non devi "scorrere tutte le scelte", perché Question ha una proprietà choices . Quindi, seleziona una scelta da eliminare, ottieni il suo riferimento Question , ottieni il riferimento alle scelte di quella domanda. Ora hai tutte le opzioni.

Il design della classe non è il design del database

Choice c1 = new Choice(question, "red"); // or just: questionId instead of question?

Questo, et.al. sembra che tu voglia che il tuo design della classe rifletta la progettazione del database. Considera questa domanda StackOverflow

    
risposta data 02.11.2014 - 06:14
fonte

Leggi altre domande sui tag