Modélisation du domaine

Au cœur de toute application orientée domaine se trouve le modèle qui représente la connaissance centrale et les règles métier du système. Bien modéliser le domaine signifie traduire les concepts du monde réel en structures logicielles expressives, cohérentes et consistantes.

Entités

Une entité est un objet défini principalement par son identité et non uniquement par ses attributs. Même si les attributs changent au fil du temps, l'identité d'une entité reste la même.

Caractéristiques principales :

  • Possède une identité unique (généralement un Id).
  • Ce qui importe, c'est qui est l'entité, pas seulement ce qu'elle contient.
  • Ses attributs peuvent changer au fil du temps.

Créer une entité avec Lino

Pour créer une nouvelle entité en utilisant Lino, exécutez :

lino entity new

L'assistant CLI vous demandera :

  • Service – Le service dans lequel l'entité sera créée.
  • Module – Le module dans lequel l'entité sera créée (uniquement dans les services modulaires).
  • Nom de l'entité – Le nom utilisé dans le domaine et dans la table de la base de données.

Ensuite, vous définirez les champs qui composent l'entité en configurant chacun d'eux.

Types de champs disponibles

Type Description Plage / Observations
shortEntier 16 bits-32 768 → 32 767
intEntier 32 bits-2 147 483 648 → 2 147 483 647
longEntier 64 bits-9 223 372 036 854 775 808 → 9 223 372 036 854 775 807
stringTexteJusqu'à environ 2 milliards de caractères
boolValeur booléennetrue ou false
GuidIdentifiant global uniqueUnicité distribuée
decimalNombre décimal haute précisionIdéal pour valeurs monétaires
floatNombre flottant (32 bits)≈ 6–9 chiffres de précision
doubleNombre flottant (64 bits)≈ 15–17 chiffres de précision
DateTimeDate et heureInclut le fuseau horaire
DateOnlySeulement la date (C# 10+)
TimeOnlySeulement l'heure (C# 10+)
EntityRéférence à une autre entité1:1 ou 1:N
Value ObjectObjet valeur immuableEx.: Adresse, CPF
EnumÉnumérationEnsemble fixe de valeurs
List<Entity>Liste d'entités1:N
ManyToManyPlusieurs-à-plusieursNécessite une table de jointure

Exemple

Création de l'entité Person :

┌────┬────┬───────────────┬────────┬────────┬───────────┬────────────────┐
│ PK │ FK │ Property name │ Type   │ Length │ Required  │ Auto-increment │
├────┼────┼───────────────┼────────┼────────┼───────────┼────────────────┤
│ x  │    │ Id            │ int    │        │     x     │       x        │
├────┼────┼───────────────┼────────┼────────┼───────────┼────────────────┤
│    │    │ Name          │ string │  100   │     x     │                │
└────┴────┴───────────────┴────────┴────────┴───────────┴────────────────┘

Structure générée par 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

Après avoir défini vos entités, utilisez Lino lui-même pour gérer les Migrations et garder la base de données synchronisée. Ce processus sera détaillé dans la section Couche de Persistance.

Objets de Valeur

Un objet de valeur représente un concept du domaine défini uniquement par ses attributs – il ne possède pas d’identité propre. Deux objets de valeur sont considérés comme égaux si toutes leurs valeurs sont identiques.

Principales caractéristiques :

  • Immuables après création.
  • Ne possèdent pas de Id.

Créer un objet de valeur avec Lino

Exécutez :

lino value-object new

Le CLI demandera :

  • Service – Service dans lequel l’objet sera créé.
  • Module – Module dans lequel l’objet sera créé (uniquement dans les services modulaires).
  • Emplacement – Racine du domaine ou agrégat spécifique.
  • Nom de l’objet de valeur.

Puis définissez les champs qui composent l’objet.

Types de champs disponibles

TypeDescriptionRemarques
shortEntier 16 bits-32 768 → 32 767
intEntier 32 bits-2 147 483 648 → 2 147 483 647
longEntier 64 bits-9 223 372 036 854 775 808 → 9 223 372 036 854 775 807
stringTexteJusqu’à ~2 milliards de caractères
boolBooléentrue/false
decimalDécimal précisValeurs monétaires
floatNombre à virgule flottante (32 bits)≈ 6–9 chiffres
doubleNombre à virgule flottante (64 bits)≈ 15–17 chiffres
DateTimeDate/heureInclut le fuseau horaire
DateOnlySeulement la dateC# 10+
TimeOnlySeulement l’heureC# 10+

Exemple

Objet de valeur 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     │
└───────────────┴────────┴────────┴───────────┘

Structure des fichiers générée (agrégat 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

Comme pour les entités, les Migrations peuvent être gérées par Lino pour maintenir la synchronisation du modèle de données.

Énumérations

Les énumérations en DDD peuvent aller au-delà des enum traditionnels de C#. Elles peuvent être des objets riches représentant des états fixes, contenant des validations, des méthodes auxiliaires et même des comportements.

Motivation :

  • Les enum de C# sont limités à une valeur entière ou chaîne.
  • Modéliser une Enumeration comme une classe offre plus de flexibilité et d’expressivité.

Caractéristiques principales :

  • Ce sont des classes héritant d’une base commune et encapsulant Id et Nom.
  • Elles permettent d’ajouter des validations, des méthodes auxiliaires et des comportements.

Créer une énumération avec Lino

Exécutez :

lino enum new

L’assistant vous demandera :

  • Service.
  • Module (si applicable).
  • Emplacement – racine du domaine ou agrégat.
  • Nom de l’énumération.
  • Typeenum traditionnel ou Smart Enum (class).
  • Stockageint ou string en base de données.

Exemple

Énumération PersonStatus :

┌───────┬───────────┬──────────────┐
│ Value │ Name      │ Display Name │
├───────┼───────────┼──────────────┤
│ 1     │ Active    │ Active       │
├───────┼───────────┼──────────────┤
│ 2     │ Inactive  │ Inactive     │
├───────┼───────────┼──────────────┤
│ 3     │ Suspended │ Suspended    │
├───────┼───────────┼──────────────┤
│ 4     │ Deleted   │ Deleted      │
└───────┴───────────┴──────────────┘

Structure générée :

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

Stocker la valeur d’une énumération comme string est valide et peut améliorer la lisibilité, mais tend à être moins efficace en termes de performances et de stockage. C’est pourquoi nous recommandons de stocker la valeur comme int, et pour maintenir l’intégrité référentielle et faciliter la maintenance, de créer une entité (table) auxiliaire dont la clé primaire correspond à la valeur de l’énumération.

Après avoir défini les énumérations, utilisez Lino pour générer et appliquer les Migrations, garantissant que la base de données reflète le modèle de domaine. Voir les détails dans la section Couche de Persistance.

Une erreur non gérée est survenue. Rafraîchir 🗙