Моделирование домена
В сердце любого приложения, ориентированного на предметную область, находится модель, которая представляет собой основное знание и бизнес-правила системы. Хорошее моделирование предметной области означает преобразование концепций реального мира в выразительные, связные и последовательные структуры программного обеспечения.
Сущности
Сущность — это объект, который определяется главным образом своей идентичностью, а не только своими атрибутами. Даже если атрибуты меняются со временем, идентичность сущности остается неизменной.
Основные характеристики:
- Имеет уникальную идентичность (обычно
Id
). - Важен именно кто сущность, а не только что она содержит.
- Её атрибуты могут изменяться со временем.
Создание сущности с помощью Lino
Для создания новой сущности с использованием Lino выполните:
lino entity new
CLI помощник запросит:
- Сервис – сервис, в котором будет создана сущность.
- Модуль – модуль, в котором будет создана сущность (только для модульных сервисов).
- Имя сущности – имя, используемое в домене и таблице базы данных.
Затем вы определите поля, которые составляют сущность, настроив каждое из них.
Доступные типы полей
Тип | Описание | Диапазон / Примечания |
---|---|---|
short | Целое число 16 бит | -32 768 → 32 767 |
int | Целое число 32 бита | -2 147 483 648 → 2 147 483 647 |
long | Целое число 64 бита | -9 223 372 036 854 775 808 → 9 223 372 036 854 775 807 |
string | Текст | До ~2 миллиардов символов |
bool | Булево значение | true или false |
Guid | Глобальный уникальный идентификатор | Распределённая уникальность |
decimal | Десятичное число с высокой точностью | Идеально для денежных значений |
float | Число с плавающей точкой (32 бита) | ≈ 6–9 знаков точности |
double | Число с плавающей точкой (64 бита) | ≈ 15–17 знаков точности |
DateTime | Дата и время | Включая часовой пояс |
DateOnly | Только дата (C# 10+) | – |
TimeOnly | Только время (C# 10+) | – |
Entity | Ссылка на другую сущность | 1 : 1 или 1 : N |
Value Object | Неизменяемый объект значения | Например: адрес, CPF |
Enum | Перечисление | Фиксированный набор значений |
List<Entity> | Список сущностей | 1 : N |
ManyToMany | Многие-ко-многим | Требуется таблица связей |
Пример
Создание сущности Person
:
┌────┬────┬───────────────┬────────┬────────┬───────────┬────────────────┐ │ PK │ FK │ Property name │ Type │ Length │ Required │ Auto-increment │ ├────┼────┼───────────────┼────────┼────────┼───────────┼────────────────┤ │ x │ │ Id │ int │ │ x │ x │ ├────┼────┼───────────────┼────────┼────────┼───────────┼────────────────┤ │ │ │ Name │ string │ 100 │ x │ │ └────┴────┴───────────────┴────────┴────────┴───────────┴────────────────┘
Структура, сгенерированная 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
После определения сущностей используйте сам Lino для управления Migrations и синхронизации базы данных. Мы подробно рассмотрим этот процесс в разделе «Слой Персистенции».
Объекты значения
Объект значения представляет собой концепцию домена, определяемую только своими атрибутами – у него нет собственной идентичности. Два объекта значения считаются равными, если все их значения совпадают.
Основные характеристики:
- Неизменяемы после создания.
- Не имеют
Id
.
Создание объекта значения с помощью Lino
Выполните:
lino value-object new
CLI запросит:
- Сервис – Сервис, в котором будет создан объект.
- Модуль – Модуль, в котором будет создан объект (только для модульных сервисов).
- Расположение – Корень домена или конкретный агрегат.
- Имя объекта значения.
Затем определите поля, которые составляют объект.
Доступные типы полей
Тип | Описание | Примечания |
---|---|---|
short | 16-битное целое | -32 768 → 32 767 |
int | 32-битное целое | -2 147 483 648 → 2 147 483 647 |
long | 64-битное целое | -9 223 372 036 854 775 808 → 9 223 372 036 854 775 807 |
string | Текст | До ~2 миллиардов символов |
bool | Булево | true /false |
decimal | Точный десятичный | Денежные значения |
float | Число с плавающей точкой (32 бита) | ≈ 6–9 цифр |
double | Число с плавающей точкой (64 бита) | ≈ 15–17 цифр |
DateTime | Дата/время | Включая часовой пояс |
DateOnly | Только дата | C# 10+ |
TimeOnly | Только время | C# 10+ |
Пример
Объект значения 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 │ └───────────────┴────────┴────────┴───────────┘
Структура сгенерированных файлов (агрегат 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
Как и в сущностях, Migrations могут управляться Lino для поддержания синхронизации модели данных.
Перечисления
Перечисления в DDD могут выходить за рамки традиционных enum
в C#. Они могут быть богатыми объектами,
представляющими фиксированные состояния, содержащими валидации, вспомогательные методы и даже поведение.
Мотивация:
- C#
enum
ограничены целочисленным или строковым значением. - Моделирование перечисления как класса предоставляет большую гибкость и выразительность.
Основные характеристики:
- Это классы, наследующиеся от общего базового класса и инкапсулирующие
Id
иИмя
. - Позволяют добавлять валидации, вспомогательные методы и поведение.
Создание перечисления с помощью Lino
Выполните:
lino enum new
Мастер запросит:
- Сервис.
- Модуль (если применимо).
- Расположение – корень домена или агрегат.
- Имя перечисления.
- Тип – традиционный
enum
или Smart Enum (class
). - Хранение –
int
илиstring
в базе данных.
Пример
Перечисление PersonStatus
:
┌───────┬───────────┬──────────────┐ │ Value │ Name │ Display Name │ ├───────┼───────────┼──────────────┤ │ 1 │ Active │ Active │ ├───────┼───────────┼──────────────┤ │ 2 │ Inactive │ Inactive │ ├───────┼───────────┼──────────────┤ │ 3 │ Suspended │ Suspended │ ├───────┼───────────┼──────────────┤ │ 4 │ Deleted │ Deleted │ └───────┴───────────┴──────────────┘
Сгенерированная структура:
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
Хранить значение перечисления как string
допустимо и может улучшить читаемость, но обычно менее эффективно по производительности и хранению.
Поэтому рекомендуется хранить значение как int
, а для сохранения ссылочной целостности и облегчения сопровождения создать вспомогательную сущность (таблицу),
где первичный ключ соответствует значению перечисления.
После определения перечислений используйте Lino для генерации и применения Migrations, гарантируя, что база данных отражает модель домена. Подробнее см. в разделе Слой Персистентности.