Modellare il dominio
Al cuore di qualsiasi applicazione guidata dal dominio cβΓ¨ il modello che rappresenta la conoscenza centrale e le regole di business del sistema. Modellare bene il dominio significa tradurre i concetti del mondo reale in strutture software espressive, coese e consistenti.
EntitΓ
Un'entitΓ Γ¨ un oggetto definito principalmente dalla sua identitΓ e non solo dai suoi attributi. Anche se gli attributi cambiano nel tempo, l'identitΓ di un'entitΓ rimane la stessa.
Caratteristiche principali:
- Possiede un'identitΓ unica (di solito un
Id
). - CiΓ² che conta Γ¨ chi Γ¨ l'entitΓ , non solo cosa contiene.
- I suoi attributi possono cambiare nel tempo.
Creare un'entitΓ con Lino
Per creare una nuova entitΓ usando Lino, esegui:
lino entity new
Il wizard CLI ti chiederΓ :
- Servizio β Il servizio in cui l'entitΓ sarΓ creata.
- Modulo β Il modulo in cui sarΓ creata l'entitΓ (solo per servizi modulari).
- Nome dell'entitΓ β Il nome usato nel dominio e nella tabella del database.
Successivamente, definirai i campi che compongono l'entitΓ configurando ciascuno di essi.
Tipi di campi disponibili
Tipo | Descrizione | Intervallo / Note |
---|---|---|
short | Intero a 16 bit | -32.768 β 32.767 |
int | Intero a 32 bit | -2.147.483.648 β 2.147.483.647 |
long | Intero a 64 bit | -9.223.372.036.854.775.808 β 9.223.372.036.854.775.807 |
string | Testo | Fino a circa 2 miliardi di caratteri |
bool | Valore booleano | true o false |
Guid | Identificatore globale univoco | UnicitΓ distribuita |
decimal | Numero decimale ad alta precisione | Ideale per valori monetari |
float | Punto flottante (32 bit) | β 6β9 cifre di precisione |
double | Punto flottante (64 bit) | β 15β17 cifre di precisione |
DateTime | Data e ora | Include il fuso orario |
DateOnly | Solo data (C# 10+) | β |
TimeOnly | Solo ora (C# 10+) | β |
Entity | Riferimento a un'altra entitΓ | 1:1 o 1:N |
Value Object | Oggetto di valore immutabile | Es.: Indirizzo, CPF |
Enum | Enumerazione | Insieme fisso di valori |
List<Entity> | Lista di entitΓ | 1:N |
ManyToMany | Molti-a-molti | Richiede tabella di join |
Esempio
Creazione dell'entitΓ Person
:
ββββββ¬βββββ¬ββββββββββββββββ¬βββββββββ¬βββββββββ¬ββββββββββββ¬βββββββββββββββββ β PK β FK β Property name β Type β Length β Required β Auto-increment β ββββββΌβββββΌββββββββββββββββΌβββββββββΌβββββββββΌββββββββββββΌβββββββββββββββββ€ β x β β Id β int β β x β x β ββββββΌβββββΌββββββββββββββββΌβββββββββΌβββββββββΌββββββββββββΌβββββββββββββββββ€ β β β Name β string β 100 β x β β ββββββ΄βββββ΄ββββββββββββββββ΄βββββββββ΄βββββββββ΄ββββββββββββ΄βββββββββββββββββ
Struttura generata da Lino:
MyApp/ βββ src/ βββ Services/ βββ MyService/ βββ Domain/ βββ MyApp.MyService.Domain.csproj βββ Aggregates/ βββ People/ βββ Person.cs βββ Errors/ β βββ PersonErrors.cs βββ Repositories/ β βββ IPersonRepository.cs βββ Resources/ βββ Person/ βββ PersonResources.resx βββ PersonResources.en.resx βββ PersonResources.pt-BR.resx
Dopo aver definito le tue entitΓ , usa Lino stesso per gestire le Migrations e mantenere sincronizzato il database. Questo processo sarΓ trattato in dettaglio nella sezione Layer di Persistenza.
Oggetti di Valore
Un oggetto di valore rappresenta un concetto di dominio definito solo dai suoi attributi β non possiede unβidentitΓ propria. Due oggetti di valore sono considerati uguali se tutti i loro valori sono uguali.
Caratteristiche principali:
- Immutabili dopo la creazione.
- Non possiedono
Id
.
Creare un oggetto di valore con Lino
Esegui:
lino value-object new
Il CLI chiederΓ :
- Servizio β Servizio in cui sarΓ creato lβoggetto.
- Modulo β Modulo in cui sarΓ creato lβoggetto (solo nei servizi modulari).
- Posizione β Radice del dominio o specifico aggregato.
- Nome dellβoggetto di valore.
Quindi definisci i campi che compongono lβoggetto.
Tipi di campo disponibili
Tipo | Descrizione | Note |
---|---|---|
short | Intero a 16 bit | -32.768 β 32.767 |
int | Intero a 32 bit | -2.147.483.648 β 2.147.483.647 |
long | Intero a 64 bit | -9.223.372.036.854.775.808 β 9.223.372.036.854.775.807 |
string | Testo | Fino a ~2 miliardi di caratteri |
bool | Booleano | true /false |
decimal | Decimale preciso | Valori monetari |
float | Virgola mobile (32 bit) | β 6β9 cifre |
double | Virgola mobile (64 bit) | β 15β17 cifre |
DateTime | Data/ora | Include fuso orario |
DateOnly | Solo data | C# 10+ |
TimeOnly | Solo ora | C# 10+ |
Esempio
Oggetto di valore Address
:
βββββββββββββββββ¬βββββββββ¬βββββββββ¬ββββββββββββ β Property name β Type β Length β Required β βββββββββββββββββΌβββββββββΌβββββββββΌββββββββββββ€ β Street β string β 100 β x β βββββββββββββββββΌβββββββββΌβββββββββΌββββββββββββ€ β Number β string β 10 β x β βββββββββββββββββΌβββββββββΌβββββββββΌββββββββββββ€ β Neighborhood β string β 50 β β βββββββββββββββββΌβββββββββΌβββββββββΌββββββββββββ€ β City β string β 100 β x β βββββββββββββββββΌβββββββββΌβββββββββΌββββββββββββ€ β State β string β 2 β x β βββββββββββββββββΌβββββββββΌβββββββββΌββββββββββββ€ β PostalCode β string β 20 β x β βββββββββββββββββΌβββββββββΌβββββββββΌββββββββββββ€ β Country β string β 100 β x β βββββββββββββββββ΄βββββββββ΄βββββββββ΄ββββββββββββ
Struttura dei file generata (aggregato Person
):
MyApp/ βββ src/ βββ Services/ βββ MyService/ βββ Domain/ βββ MyApp.MyService.Domain.csproj βββ Aggregates/ βββ People/ βββ Person.cs βββ ValueObjects/ β βββ Address.cs βββ Errors/ β βββ AddressErrors.cs β βββ PersonErrors.cs βββ Repositories/ β βββ IPersonRepository.cs βββ Resources/ βββ Address/ β βββ AddressResources.resx β βββ AddressResources.en.resx β βββ AddressResources.pt-BR.resx βββ Person/ βββ PersonResources.resx βββ PersonResources.en.resx βββ PersonResources.pt-BR.resx
Come per le entitΓ , le Migrations possono essere gestite da Lino per mantenere il modello dati sincronizzato.
Enumerazioni
Le enumerazioni nel DDD possono andare oltre i tradizionali enum
di C#. Possono essere oggetti ricchi
che rappresentano stati fissi, contenenti validazioni, metodi ausiliari e persino comportamenti.
Motivazione:
- I
enum
di C# sono limitati a un valore intero o stringa. - Modellare un'Enumeration come classe offre maggiore flessibilitΓ ed espressivitΓ .
Caratteristiche principali:
- Sono classi che ereditano da una base comune e incapsulano
Id
eNome
. - Permettono di aggiungere validazioni, metodi ausiliari e comportamenti.
Creare un'enumerazione con Lino
Esegui:
lino enum new
L'assistente richiederΓ :
- Servizio.
- Modulo (se applicabile).
- Posizione β radice del dominio o aggregato.
- Nome dell'enumerazione.
- Tipo β
enum
tradizionale o Smart Enum (class
). - Archiviazione β
int
ostring
nel database.
Esempio
Enumerazione PersonStatus
:
βββββββββ¬ββββββββββββ¬βββββββββββββββ β Value β Name β Display Name β βββββββββΌββββββββββββΌβββββββββββββββ€ β 1 β Active β Active β βββββββββΌββββββββββββΌβββββββββββββββ€ β 2 β Inactive β Inactive β βββββββββΌββββββββββββΌβββββββββββββββ€ β 3 β Suspended β Suspended β βββββββββΌββββββββββββΌβββββββββββββββ€ β 4 β Deleted β Deleted β βββββββββ΄ββββββββββββ΄βββββββββββββββ
Struttura generata:
MyApp/ βββ src/ βββ Services/ βββ MyService/ βββ Domain/ βββ MyApp.MyService.Domain.csproj βββ Aggregates/ βββ People/ βββ Person.cs βββ Enums/ β βββ PersonStatus.cs βββ ValueObjects/ β βββ Address.cs βββ Errors/ β βββ AddressErrors.cs β βββ PersonErrors.cs βββ Repositories/ β βββ IPersonRepository.cs βββ Resources/ βββ Address/ β βββ AddressResources.resx β βββ AddressResources.en.resx β βββ AddressResources.pt-BR.resx βββ Person/ β βββ PersonResources.resx β βββ PersonResources.en.resx β βββ PersonResources.pt-BR.resx βββ PersonStatus/ βββ PersonStatusResources.resx βββ PersonStatusResources.en.resx βββ PersonStatusResources.pt-BR.resx
Archiviare il valore di un'enumerazione come string
Γ¨ valido e puΓ² migliorare la leggibilitΓ , ma tende ad essere meno efficiente in termini di prestazioni e spazio di archiviazione.
Per questo, consigliamo di archiviare il valore come int
e, per mantenere l'integritΓ referenziale e facilitare la manutenzione, creare un'entitΓ (tabella) ausiliaria dove la chiave primaria corrisponda al valore dell'enumerazione.
Dopo aver definito le enumerazioni, usa Lino per generare e applicare le Migrations, garantendo che il database rifletta il modello di dominio. Vedi i dettagli nella sezione Layer di Persistenza.