Modelando o domínio

No coraΓ§Γ£o de qualquer aplicaΓ§Γ£o orientada a domΓ­nio estΓ‘ o modelo que representa o conhecimento central e as regras de negΓ³cio do sistema. Modelar bem o domΓ­nio significa traduzir conceitos do mundo real em estruturas de software expressivas, coesas e consistentes.

Entidades

Uma entidade Γ© um objeto definido principalmente pela sua identidade e nΓ£o apenas pelos seus atributos. Mesmo que os atributos mudem ao longo do tempo, a identidade de uma entidade permanece a mesma.

CaracterΓ­sticas principais:

  • Possui uma identidade ΓΊnica (geralmente um Id).
  • Aquilo que importa Γ© quem a entidade Γ©, nΓ£o apenas o que ela contΓ©m.
  • Seus atributos podem mudar ao longo do tempo.

Criando uma entidade com o Lino

Para criar uma nova entidade utilizando o Lino, execute:

lino entity new

O assistente do CLI solicitarΓ‘:

  • ServiΓ§o – ServiΓ§o no qual a entidade serΓ‘ criada.
  • MΓ³dulo – MΓ³dulo em que a entidade serΓ‘ criada (apenas em serviΓ§os modulares).
  • Nome da entidade – Nome utilizado no domΓ­nio e na tabela do banco de dados.

Em seguida, vocΓͺ definirΓ‘ os campos que compΓ΅em a entidade, configurando cada um deles.

Tipos de campos disponΓ­veis

Tipo DescriΓ§Γ£o Faixa / ObservaΓ§Γ΅es
shortInteiro de 16 bits-32β€―768  β†’  32β€―767
intInteiro de 32 bits-2β€―147β€―483β€―648  β†’  2β€―147β€―483β€―647
longInteiro de 64 bits-9β€―223β€―372β€―036β€―854β€―775β€―808  β†’  9β€―223β€―372β€―036β€―854β€―775β€―807
stringTextoAtΓ© ~2 bilhΓ΅es de caracteres
boolValor booleanotrue ou false
GuidIdentificador global ΓΊnicoUnicidade distribuΓ­da
decimalNΓΊmero decimal de alta precisΓ£oIdeal p/ valores monetΓ‘rios
floatPonto flutuante (32 bits)β‰ˆβ€―6–9 dΓ­gitos de precisΓ£o
doublePonto flutuante (64 bits)β‰ˆβ€―15–17 dΓ­gitos de precisΓ£o
DateTimeData e horaInclui fuso horΓ‘rio
DateOnlySΓ³ data (C#Β 10+)–
TimeOnlySΓ³ hora (C#Β 10+)–
EntityReferΓͺncia a outra entidade1 : 1 ou 1 : N
Value ObjectObjeto de valor imutΓ‘velEx.: EndereΓ§o, CPF
EnumEnumeraΓ§Γ£oConjunto fixo de valores
List<Entity>Lista de entidades1 : N
ManyToManyMuitos‑para‑muitosRequer tabela de junΓ§Γ£o

Exemplo

Criando a entidade Person:

β”Œβ”€β”€β”€β”€β”¬β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ PK β”‚ FK β”‚ Property name β”‚ Type   β”‚ Length β”‚ Required  β”‚ Auto-increment β”‚
β”œβ”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ x  β”‚    β”‚ Id            β”‚ int    β”‚        β”‚     x     β”‚       x        β”‚
β”œβ”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚    β”‚    β”‚ Name          β”‚ string β”‚  100   β”‚     x     β”‚                β”‚
β””β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Estrutura gerada pelo 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

Depois de definir suas entidades, use o prΓ³prio Lino para gerenciar as Migrations e manter o banco de dados sincronizado. Abordaremos esse processo em detalhes na seΓ§Γ£o Camada de PersistΓͺncia.

Objetos de Valor

Um objeto de valor representa um conceito do domΓ­nio definido apenas pelos seus atributos – ele nΓ£o possui identidade prΓ³pria. Dois objetos de valor sΓ£o considerados iguais se todos os seus valores forem iguais.

CaracterΓ­sticas principais:

  • ImutΓ‘veis apΓ³s a criaΓ§Γ£o.
  • NΓ£o possuem Id.

Criando um objeto de valor com o Lino

Execute:

lino value-object new

O CLI solicitarΓ‘:

  • ServiΓ§o – ServiΓ§o no qual o objeto serΓ‘ criado.
  • MΓ³dulo – MΓ³dulo em que o objeto serΓ‘ criado (apenas em serviΓ§os modulares).
  • LocalizaΓ§Γ£o – Raiz do domΓ­nio ou agregado especΓ­fico.
  • Nome do objeto de valor.

Em seguida, defina os campos que compΓ΅em o objeto.

Tipos de campos disponΓ­veis

TipoDescriΓ§Γ£oObservaΓ§Γ΅es
shortInteiro de 16 bits-32β€―768  β†’  32β€―767
intInteiro de 32 bits-2β€―147β€―483β€―648  β†’  2β€―147β€―483β€―647
longInteiro de 64 bits-9β€―223β€―372β€―036β€―854β€―775β€―808  β†’  9β€―223β€―372β€―036β€―854β€―775β€―807
stringTextoAtΓ© ~2 bilhΓ΅es de caracteres
boolBooleanotrue/false
decimalDecimal precisoValores monetΓ‘rios
floatPonto flutuante (32 bits)β‰ˆβ€―6–9 dΓ­gitos
doublePonto flutuante (64 bits)β‰ˆβ€―15–17 dΓ­gitos
DateTimeData/horaInclui fuso
DateOnlySomente dataC#Β 10+
TimeOnlySomente horaC#Β 10+

Exemplo

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     β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Estrutura de arquivos gerada (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

Assim como nas entidades, as Migrations podem ser gerenciadas pelo Lino para manter o modelo de dados em sincronia.

EnumeraΓ§Γ΅es

As enumeraΓ§Γ΅es em DDD podem ir alΓ©m dos enum tradicionais do C#. Elas podem ser objetos ricos que representam estados fixos, contendo validaΓ§Γ΅es, mΓ©todos auxiliares e atΓ© comportamento.

MotivaΓ§Γ£o:

  • Os enum do C# sΓ£o limitados a um valor inteiro ou string.
  • Modelar uma Enumeration como classe oferece maior flexibilidade e expressividade.

CaracterΓ­sticas principais:

  • SΓ£o classes que herdam de uma base comum e encapsulam Id e Nome.
  • Permitem adicionar validaΓ§Γ΅es, mΓ©todos auxiliares e comportamento.

Criando uma enumeraΓ§Γ£o com o Lino

Execute:

lino enum new

O assistente solicitarΓ‘:

  • ServiΓ§o.
  • MΓ³dulo (se aplicΓ‘vel).
  • LocalizaΓ§Γ£o – Raiz do domΓ­nio ou agregado.
  • Nome da enumeraΓ§Γ£o.
  • Tipo – enum tradicional ou Smart Enum (class).
  • Armazenamento – int ou string no banco de dados.

Exemplo

EnumeraΓ§Γ£o PersonStatus:

β”Œβ”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Value β”‚ Name      β”‚ Display Name β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ 1     β”‚ Active    β”‚ Active       β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ 2     β”‚ Inactive  β”‚ Inactive     β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ 3     β”‚ Suspended β”‚ Suspended    β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ 4     β”‚ Deleted   β”‚ Deleted      β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Estrutura gerada:

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

Armazenar o valor de uma enumeraΓ§Γ£o como string Γ© vΓ‘lido e pode melhorar a legibilidade, mas tende a ser menos eficiente em termos de desempenho e armazenamento. Por isso, recomendamos armazenar o valor como int, e, para manter a integridade referencial e facilitar a manutenΓ§Γ£o, criar uma entidade (tabela) auxiliar onde a chave primΓ‘ria corresponda ao valor da enumeraΓ§Γ£o.

ApΓ³s definir as enumeraΓ§Γ΅es, utilize o Lino para gerar e aplicar as Migrations, garantindo que o banco de dados reflita o modelo de domΓ­nio. Veja detalhes na seΓ§Γ£o Camada de PersistΓͺncia.

Ocorreu um erro não tratado. Recarregar πŸ—™