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
shortEntero de 16 bits-32 768 β†’ 32 767
intEntero de 32 bits-2 147 483 648 β†’ 2 147 483 647
longEntero de 64 bits-9 223 372 036 854 775 808 β†’ 9 223 372 036 854 775 807
stringTextoHasta ~2 mil millones de caracteres
boolValor booleanotrue o false
GuidIdentificador global ΓΊnicoUnicidad distribuida
decimalNΓΊmero decimal de alta precisiΓ³nIdeal para valores monetarios
floatPunto flotante (32 bits)β‰ˆ 6–9 dΓ­gitos de precisiΓ³n
doublePunto flotante (64 bits)β‰ˆ 15–17 dΓ­gitos de precisiΓ³n
DateTimeFecha y horaIncluye zona horaria
DateOnlySΓ³lo fecha (C# 10+)–
TimeOnlySΓ³lo hora (C# 10+)–
EntityReferencia a otra entidad1:1 o 1:N
Value ObjectObjeto de valor inmutableEj.: DirecciΓ³n, CPF
EnumEnumeraciΓ³nConjunto fijo de valores
List<Entity>Lista de entidades1:N
ManyToManyMuchos a muchosRequiere 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:

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

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.

Objetos de Valor

Un objeto de valor representa un concepto del dominio definido ΓΊnicamente por sus atributos – no posee identidad propia. Dos objetos de valor se consideran iguales si todos sus valores son iguales.

CaracterΓ­sticas principales:

  • Inmutables despuΓ©s de la creaciΓ³n.
  • No poseen Id.

Creando un objeto de valor 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 objeto de valor.

Luego, defina los campos que componen el objeto.

Tipos de campos disponibles

TipoDescripciΓ³nObservaciones
shortEntero de 16 bits-32.768 β†’ 32.767
intEntero de 32 bits-2.147.483.648 β†’ 2.147.483.647
longEntero de 64 bits-9.223.372.036.854.775.808 β†’ 9.223.372.036.854.775.807
stringTextoHasta ~2 mil millones de caracteres
boolBooleanotrue/false
decimalDecimal precisoValores monetarios
floatPunto flotante (32 bits)β‰ˆ 6–9 dΓ­gitos
doublePunto flotante (64 bits)β‰ˆ 15–17 dΓ­gitos
DateTimeFecha/horaIncluye zona horaria
DateOnlySΓ³lo fechaC# 10+
TimeOnlySΓ³lo horaC# 10+

Ejemplo

Objeto de valor 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):

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

AsΓ­ como en las entidades, las Migrations pueden ser gestionadas por Lino para mantener el modelo de datos sincronizado.

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 enum de 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 Id y Nombre.
  • Permiten agregar validaciones, mΓ©todos auxiliares y comportamiento.

Creando una enumeraciΓ³n con Lino

Ejecute:

lino enum new

El asistente solicitarΓ‘:

  • Servicio.
  • MΓ³dulo (si aplica).
  • UbicaciΓ³n – raΓ­z del dominio o agregado.
  • Nombre de la enumeraciΓ³n.
  • Tipo – enum tradicional o Smart Enum (class).
  • Almacenamiento – int o string en 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:

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

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.

Se ha producido un error no controlado. Recargar πŸ—™