Modelando el dominio
En el corazΓ³n de cualquier aplicaciΓ³n orientada al dominio estΓ‘ el modelo que representa el conocimiento central y las reglas de negocio del sistema. Modelar bien el dominio significa traducir conceptos del mundo real en estructuras de software expresivas, cohesivas y consistentes.
Entidades
Una entidad es un objeto definido principalmente por su identidad y no solo por sus atributos. Aunque los atributos cambien con el tiempo, la identidad de una entidad permanece igual.
CaracterΓsticas principales:
- Tiene una identidad ΓΊnica (generalmente un
Id). - Lo que importa es quiΓ©n es la entidad, no solo quΓ© contiene.
- Sus atributos pueden cambiar con el tiempo.
Creando una entidad con Lino
Para crear una nueva entidad utilizando Lino, ejecute:
lino entity new
El asistente del CLI solicitarΓ‘:
- Servicio β Servicio en el que se crearΓ‘ la entidad.
- MΓ³dulo β MΓ³dulo donde se crearΓ‘ la entidad (solo en servicios modulares).
- Nombre de la entidad β Nombre usado en el dominio y en la tabla de la base de datos.
Luego, definirΓ‘s los campos que componen la entidad configurando cada uno de ellos.
Tipos de campos disponibles
| Tipo | DescripciΓ³n | Rango / Observaciones |
|---|---|---|
short | Entero de 16 bits | -32 768 β 32 767 |
int | Entero de 32 bits | -2 147 483 648 β 2 147 483 647 |
long | Entero de 64 bits | -9 223 372 036 854 775 808 β 9 223 372 036 854 775 807 |
string | Texto | Hasta ~2 mil millones de caracteres |
bool | Valor booleano | true o false |
Guid | Identificador global ΓΊnico | Unicidad distribuida |
decimal | NΓΊmero decimal de alta precisiΓ³n | Ideal para valores monetarios |
float | Punto flotante (32 bits) | β 6β9 dΓgitos de precisiΓ³n |
double | Punto flotante (64 bits) | β 15β17 dΓgitos de precisiΓ³n |
DateTime | Fecha y hora | Incluye zona horaria |
DateOnly | SΓ³lo fecha (C# 10+) | β |
TimeOnly | SΓ³lo hora (C# 10+) | β |
Entity | Referencia a otra entidad | 1:1 o 1:N |
Value Object | Value Object inmutable | Ej.: DirecciΓ³n, CPF |
Enum | EnumeraciΓ³n | Conjunto fijo de valores |
List<Entity> | Lista de entidades | 1:N |
ManyToMany | Muchos a muchos | Requiere tabla de uniΓ³n |
Ejemplo
Creando la entidad Person:
ββββββ¬βββββ¬ββββββββββββββββ¬βββββββββ¬βββββββββ¬ββββββββββββ¬βββββββββββββββββ β PK β FK β Property name β Type β Length β Required β Auto-increment β ββββββΌβββββΌββββββββββββββββΌβββββββββΌβββββββββΌββββββββββββΌβββββββββββββββββ€ β x β β Id β int β β x β x β ββββββΌβββββΌββββββββββββββββΌβββββββββΌβββββββββΌββββββββββββΌβββββββββββββββββ€ β β β Name β string β 100 β x β β ββββββ΄βββββ΄ββββββββββββββββ΄βββββββββ΄βββββββββ΄ββββββββββββ΄βββββββββββββββββ
Estructura generada por Lino:
<ProjectName>/
βββ src/
βββ Services/
βββ <ServiceName>/
βββ Domain/
βββ <ProjectName>.<ServiceName>.Domain.csproj
βββ Aggregates/
βββ People/
βββ Person.cs
βββ Errors/
β βββ PersonErrors.cs
βββ Repositories/
β βββ IPersonRepository.cs
βββ Resources/
βββ Person/
βββ PersonResources.resx
βββ PersonResources.en.resx
βββ PersonResources.pt-BR.resx
DespuΓ©s de definir tus entidades, usa Lino para gestionar las Migrations y mantener la base de datos sincronizada. Este proceso se abordarΓ‘ en detalle en la secciΓ³n Capa de Persistencia.
Flujo actual de evoluciΓ³n
AdemΓ‘s del flujo interactivo con lino entity new, la CLI tambiΓ©n permite dejar explΓcita la intenciΓ³n en el comando cuando el servicio, el mΓ³dulo y el nombre ya se conocen:
lino entity new --name <EntityName> --service <ServiceName> --module <ModuleName> lino entity edit --service <ServiceName> --module <ModuleName> --entity <EntityName> lino entity list --service <ServiceName> --module <ModuleName>
Use entity list antes de crear nuevos conceptos en mΓ³dulos grandes. Durante la ediciΓ³n, revise identificador, propiedades, obligatoriedad, longitud, relaciones, Γndices, ownership, tenant e impacto en migrations.
Strongly Typed IDs, ownership e invariantes
Cuando Strongly Typed IDs estΓ‘n habilitados, el identificador pasa a ser un tipo dedicado, como ProductId, reduciendo intercambios accidentales entre IDs de entidades diferentes. Las relaciones deben reflejar el ownership real del dominio: no toda referencia necesita convertirse en navegaciΓ³n directa; en muchos casos, un identificador, shadow entity, evento de integraciΓ³n o consulta explΓcita protege mejor el lΓmite entre mΓ³dulos.
Coloque las invariantes en el dominio, no solo en la UI, en la base de datos o en validators. DespuΓ©s de cambiar entidades, ejecute un build, revise el diff y genere o actualice migrations.
Value Objects
Un Value Object representa un concepto del dominio definido ΓΊnicamente por sus atributos β no posee identidad propia. Dos Value Objects se consideran iguales si todos sus valores son iguales.
CaracterΓsticas principales:
- Inmutables despuΓ©s de la creaciΓ³n.
- No poseen
Id.
Creando un Value Object con Lino
Ejecute:
lino value-object new
El CLI solicitarΓ‘:
- Servicio β Servicio en el que se crearΓ‘ el objeto.
- MΓ³dulo β MΓ³dulo en el que se crearΓ‘ el objeto (solo en servicios modulares).
- UbicaciΓ³n β RaΓz del dominio o agregado especΓfico.
- Nombre del Value Object.
Luego, defina los campos que componen el objeto.
Tipos de campos disponibles
| Tipo | DescripciΓ³n | Observaciones |
|---|---|---|
short | Entero de 16 bits | -32.768 β 32.767 |
int | Entero de 32 bits | -2.147.483.648 β 2.147.483.647 |
long | Entero de 64 bits | -9.223.372.036.854.775.808 β 9.223.372.036.854.775.807 |
string | Texto | Hasta ~2 mil millones de caracteres |
bool | Booleano | true/false |
decimal | Decimal preciso | Valores monetarios |
float | Punto flotante (32 bits) | β 6β9 dΓgitos |
double | Punto flotante (64 bits) | β 15β17 dΓgitos |
DateTime | Fecha/hora | Incluye zona horaria |
DateOnly | SΓ³lo fecha | C# 10+ |
TimeOnly | SΓ³lo hora | C# 10+ |
Ejemplo
Value Object 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 β βββββββββββββββββ΄βββββββββ΄βββββββββ΄ββββββββββββ
Estructura de archivos generada (agregado Person):
<ProjectName>/
βββ src/
βββ Services/
βββ <ServiceName>/
βββ Domain/
βββ <ProjectName>.<ServiceName>.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
AsΓ como en las entidades, las Migrations pueden ser gestionadas por Lino para mantener el modelo de datos sincronizado.
Flujo actual de evoluciΓ³n
AdemΓ‘s del comando interactivo, use parΓ‘metros cuando ya sepa dΓ³nde debe nacer el concepto:
lino value-object new --name <ValueObjectName> --service <ServiceName> --module <ModuleName> lino value-object edit --service <ServiceName> --module <ModuleName> --value-object <ValueObjectName> lino value-object list --service <ServiceName> --module <ModuleName>
Cuando una propiedad de entidad se declara como ValueObject, Lino puede reutilizar un Value Object existente o crear uno nuevo durante el modelado de la entidad. Prefiera esta opciΓ³n cuando el conjunto de campos represente un ΓΊnico concepto, como dinero, direcciΓ³n, dimensiones, perΓodo o documento.
Persistencia, UI y localizaciΓ³n
Lino mapea propiedades de Value Objects mediante la capa de persistencia del mΓ³dulo y lleva metadatos de visualizaciΓ³n a resources. Esto permite labels y mensajes localizados para valores anidados. El Value Object pertenece al mΓ³dulo donde fue generado; no se convierte en un contrato compartido entre mΓ³dulos sin una integraciΓ³n explΓcita.
Proteja las invariantes en el propio tipo: valores negativos, moneda invΓ‘lida, perΓodos invertidos o documentos mal formados no deben nacer vΓ‘lidos.
Enumeraciones
Las enumeraciones en DDD pueden ir mΓ‘s allΓ‘ de los enum tradicionales de C#. Pueden ser objetos ricos
que representan estados fijos, conteniendo validaciones, mΓ©todos auxiliares e incluso comportamiento.
MotivaciΓ³n:
- Los
enumde C# estΓ‘n limitados a un valor entero o cadena. - Modelar una EnumeraciΓ³n como clase ofrece mayor flexibilidad y expresividad.
CaracterΓsticas principales:
- Son clases que heredan de una base comΓΊn y encapsulan
IdyNombre. - Permiten agregar validaciones, mΓ©todos auxiliares y comportamiento.
Creando una enumeraciΓ³n con Lino
Ejecute:
lino enumeration new
El asistente solicitarΓ‘:
- Servicio.
- MΓ³dulo (si aplica).
- UbicaciΓ³n β raΓz del dominio o agregado.
- Nombre de la enumeraciΓ³n.
- Tipo β
enumtradicional o Smart Enum (class). - Almacenamiento β
intostringen la base de datos.
Ejemplo
EnumeraciΓ³n PersonStatus:
βββββββββ¬ββββββββββββ¬βββββββββββββββ β Value β Name β Display Name β βββββββββΌββββββββββββΌβββββββββββββββ€ β 1 β Active β Active β βββββββββΌββββββββββββΌβββββββββββββββ€ β 2 β Inactive β Inactive β βββββββββΌββββββββββββΌβββββββββββββββ€ β 3 β Suspended β Suspended β βββββββββΌββββββββββββΌβββββββββββββββ€ β 4 β Deleted β Deleted β βββββββββ΄ββββββββββββ΄βββββββββββββββ
Estructura generada:
<ProjectName>/
βββ src/
βββ Services/
βββ <ServiceName>/
βββ Domain/
βββ <ProjectName>.<ServiceName>.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
Almacenar el valor de una enumeraciΓ³n como string es vΓ‘lido y puede mejorar la legibilidad, pero suele ser menos eficiente en tΓ©rminos de rendimiento y almacenamiento.
Por eso recomendamos almacenar el valor como int, y para mantener la integridad referencial y facilitar el mantenimiento, crear una entidad (tabla) auxiliar donde la clave primaria corresponda al valor de la enumeraciΓ³n.
DespuΓ©s de definir las enumeraciones, use Lino para generar y aplicar las Migrations, asegurando que la base de datos refleje el modelo de dominio. Vea detalles en la secciΓ³n Capa de Persistencia.
Flujo actual de evoluciΓ³n
AdemΓ‘s del comando interactivo, use parΓ‘metros cuando la ubicaciΓ³n y el nombre ya estΓ©n definidos:
lino enumeration new --name <EnumerationName> --service <ServiceName> --module <ModuleName> lino enumeration edit --service <ServiceName> --module <ModuleName> --enumeration <EnumerationName> lino enumeration list --service <ServiceName> --module <ModuleName>
Enumeration, entidad o configuraciΓ³n
| Use enumeration | Use entidad o configuraciΓ³n |
|---|---|
| Estado de pedido, estado de publicaciΓ³n, tipo tΓ©cnico de integraciΓ³n | CategorΓa administrable por usuario, motivo configurable por tenant, proveedor gestionado en backoffice |
| Valores versionados junto con el cΓ³digo | Valores modificados en runtime o controlados por permisos |
| Regla simple o pequeΓ±o comportamiento por valor | Ciclo de vida, auditorΓa, traducciΓ³n dinΓ‘mica o relaciΓ³n propia |
Si la enumeration expone un nombre de visualizaciΓ³n, Lino puede generar resources para labels localizados. Si se persiste o se usa como seed data, revise migrations despuΓ©s de agregar, eliminar o renombrar valores. La consistencia entre cΓ³digo, base de datos y UI forma parte del cambio de dominio.
