Includere i dati aggregati nella risposta al servizio web in DDD

0

Sono stato alle prese con questo problema per un po '. Supponiamo che tu abbia un'applicazione aziendale con un dominio ricco e in una delle viste front-end tu mostri un elenco di Orders aperto. In questa vista mostrate cose come orderDate, customerName, totalAmount, ... ma il client vuole anche vedere quanti oggetti sono nell'ordine (in pratica il conteggio dell'entità OrderItems). Qual è il modo migliore per gestirlo?

Ipotesi

  • La classe Order ha un List<OrderItem> che viene recuperato pigramente
  • Ogni oggetto ResponseDTO contiene solo le sue proprietà principali e qualsiasi proprietà da @ManyToOne associazioni (quindi Customer verrebbe incluso quando si preleva un Order

Soluzione 1

Puoi effettuare una chiamata di riposo per la risorsa Order chiamando /api/orders , riceverai una risposta con le proprietà principali e i dati del cliente. Per ogni ordine dovrai eseguire un nuovo recupero fino a /api/orders/<id>/items . Questo è fondamentalmente un problema N + 1 con molte chiamate HTTP.

Soluzione 2

Cambio il mio assunto iniziale e recupero avidamente le raccolte e includo immediatamente OrderItems nel ResponseDTO. La domanda diventa quindi, sto andando a prendere con entusiasmo ogni collezione di ogni entità? Questo sembra un serio problema di prestazioni. In questa soluzione il front-end dovrebbe effettuare solo 1 chiamata.

Soluzione 3

Sono in gioco le ipotesi iniziali, quindi prendo pigramente le raccolte ma sposto il problema N + 1 dal front-end al back-end (quindi nessuna chiamata HTTP aggiuntiva), non una vera soluzione ma almeno il costoso HTTP le chiamate vengono eliminate.

Soluzione 4

Nel mio modello di dominio ricco aggiungo un attributo all'entità Order chiamata numberOfItems . Ogni volta che il metodo addOrderItem(OrderItem item) viene invocato su un oggetto Order , incremento l'attributo numberOfItems . È anche memorizzato nel database. In questo modo posso avere tutte le mie ipotesi iniziali e utilizzare ResponseDTO solo con le proprietà principali e faccio solo 1 chiamata HTTP. Il problema che ho con questa soluzione è che molte persone dicono che non si dovrebbero archiviare dati aggregati come quelli nel database.

Capisco che non esiste una soluzione perfetta e dipende sempre, ma per la vita di me non riesco a trovare una buona discussione su questo problema. Quando si fa un problema su google, si trovano spesso informazioni su HATEOAS ma che si adatterebbero alla mia soluzione 1, che non credo sia davvero una soluzione.

Se qualcuno può dare una soluzione alternativa o migliorare una delle soluzioni che ho dato, sarebbe molto apprezzato.

    
posta Mekswoll 16.02.2018 - 11:31
fonte

2 risposte

1

Sono d'accordo con @ guilaume31 e consiglio di utilizzare un modello di lettura DTO / CQRS personalizzato.

Con una query di database specificata è possibile ottenere gli ordini e il numero di OrderItem in una sola query. Metti il risultato in un DTO specializzato e il gioco è fatto.

Non usare Entità per questa query!

    
risposta data 16.02.2018 - 13:38
fonte
0

A parte l'ovvia soluzione di separare semplicemente il tuo modello di comando dal tuo modello di lettura (CQRS) per consentire divergenze in termini di struttura e campi (che presumo sia fuori discussione), proporrei di adottare la soluzione 2 o 4 sopra.

Anche se dici 2 è un serio problema di prestazioni, è davvero? Quanti OrderItems sono in genere inclusi in Order ? Se il numero non è eccessivamente grande o ogni OrderItem non è particolarmente complesso, non mi aspetto un impatto troppo grande, in termini di prestazioni, qui. Inoltre, è abbastanza comune in questo dominio che Order sia un Root aggregato che include OrderItems in modo che possa applicare tutti i tipi di invarianti possibili (come il prezzo massimo, ecc.). Se fosse così, dovresti comunque seguire questa strada. Inoltre, posso anche immaginare ragionevolmente altre istanze in cui un utente vorrebbe vedere l'elenco di OrderItems in un Order (che sembra piuttosto fondamentale, non è vero?).

Se le prestazioni sono davvero un problema ed è improbabile che tu abbia bisogno di un elenco di OrderItems per qualche altra caratteristica, la soluzione 4 è la soluzione migliore. Non vi è alcun motivo per memorizzare numberOfItems come un campo nel database, tuttavia, e ciò viola i principi fondamentali del modello relazionale dell'entità (ci sarebbe più di un modo per trovare tali informazioni). L'approccio corretto consiste semplicemente nel modificare la query utilizzata per Order idratazione per calcolare il numberOfItems e fornire il conteggio nel set di risultati. La proprietà numberOfItems non deve essere utilizzata durante la persistenza.

    
risposta data 14.03.2018 - 20:31
fonte