Attualmente sto creando varie entità in ASP.NET Core 2.2 con i DTO di accompagnamento per un'API Web. L'applicazione client invierebbe un oggetto DTO all'azione del controller pertinente. Lì usando AutoMapper, questo sarebbe mappato dall'oggetto DTO a un oggetto entità. L'oggetto entità risultante verrebbe salvato in un repository di framework di entità che in questo momento sarebbe un database Microsoft SQL. Per brevità supponiamo che i fusi orari sarebbero irrilevanti in questo caso.
Mi stavo solo chiedendo quale approccio sarebbe stato più appropriato o addirittura non avere il calcolo né nel DTO o nell'entità, ma forse all'interno dell'azione del controller.
Nota: il codice attuale è più complicato e comporta vari calcoli per varie proprietà, ho semplicemente scelto un semplice caso per illustrare la mia domanda.
Approccio n. 1
// Entity
public class EventTimes
{
public DateTime Start { get; set; }
public DateTime End { get; set; }
public decimal TotalHours => (decimal)(End - Start).TotalHours;
}
// DTO
public class EventTimesDto
{
public DateTime Start { get; set; }
public DateTime End { get; set; }
}
Approccio n. 2
// Entity
public class EventTimes
{
public DateTime Start { get; set; }
public DateTime End { get; set; }
public decimal TotalHours { get; set; }
}
// DTO
public class EventTimesDto
{
public DateTime Start { get; set; }
public DateTime End { get; set; }
public decimal TotalHours => (decimal)(End - Start).TotalHours;
}
Dipende dal contesto reale. EventTimes
un'entità o fa piuttosto parte del tuo modello di dominio?
In entrambi i casi non lo inserirei in dto poiché questo è davvero solo per il trasferimento di dati, quindi non dovrebbe contenere alcuna logica (oltre forse la convalida).
Poiché la responsabilità di questo calcolo non fa parte del dto, né del modello di entità, è possibile inserire il calcolo pesante in un EventTimesCalculator
questo modo:
public class EventTimesCalculator
{
public decimal CalculateTotalHours(EventTimes eventTimes)
{
return (decimal)(eventTimes.End - eventTimes.Start).TotalHours;
}
}
Se EventTimes
fa parte del tuo livello aziendale / modello di dominio, un modo più appropriato sarebbe quello di avere un metodo GetTotalHours()
all'interno del modello, anziché una proprietà. Ovviamente, se si desidera salvare tali informazioni, è necessario mapparlo sul modello di persistenza. Inoltre, dal momento che queste informazioni possono essere calcolate, non è necessario persistere affatto, principalmente perché la logica potrebbe cambiare (esempio: escludere interruzioni, interruzioni o simili).
Il mio consiglio è di smettere di pensare in termini di entità di database (che presumo tu intendessi sopra).
Alla fine, è piuttosto un dettaglio in cui metti la logica di calcolo, cosa ancora più importante è avere un design semplice. Il monolitico dell'applicazione inserisce quella logica nel tuo livello che contiene la logica aziendale? È un'architettura distribuita, gestire il calcolo per il modello nel servizio responsabile di Eventing. È solo una piccola API, mantienila semplice, mettila dove te o il tuo team ti aspetteresti di più.
Sto usando il secondo approccio perché l'entità può contenere raw che può essere modificata dal flusso dell'applicazione.
Il modello Common Data Transfer Object (DTO) è esattamente ciò che si desidera per i dati di trasporto tra i livelli dell'applicazione che può trasformare i dati nell'output desiderato. Non può contenere la logica aziendale ma può anche "preparare", "ridurre" i dati necessari per la destinazione.
Per esempio:
Se il livello di presentazione necessita di TotalHours, lo faccio nel modello anziché nell'entità. Fare questo in entità porterebbe a infinite modifiche.
Un altro esempio può essere il nome completo dell'utente Firstname
, Lastname
, AcademicDegree
.
L'entità può tenerli tutti ma
È bene mantenere proprietà che rendono il formato desiderato in DTO specifico anziché in IMHO entità.
Io in ASP.NET Core faccio questo nell'architettura di cipolla e visualizzo i modelli e dalla mia esperienza è facile da gestire, modificare, preparare i dati per front-end o layer invece di cambiare qualcosa nel core.
Se qualcuno non è d'accordo con me, lascia un commento che mi piace imparare qualcosa di nuovo.
Spero che sia d'aiuto