Este documento descreve as bibliotecas de domínio e foca em como modelar entidades e agregados, separando o conteúdo de persistência (WorkContext/UnitOfWork/Repositories), que está documentado em .docs/workcontext.md.
Escopo:
RoyalCode.EntitiesRoyalCode.Aggregates
Compatibilidade: múltiplos targets (.NET 8, .NET 9 e .NET 10) via $(LibTargets).
Fundação para modelagem de entidades. Fornece contratos e implementações básicas para ID, Code, Guid, estado ativo e exclusão lógica.
Principais tipos
IEntity/IEntity<TId>: marca uma entidade e o tipo do seu identificador.Entity<TId>: base com propriedadeId(set protegido).Entity<TId, TCode>: base comIdeCode.IHasId<TId>: expõeIdpara entidades/DTOs.IHasCode<TCode>: expõeCode(identificador amigável e único, distinto do ID).IHasGuid: expõeGuidglobal (não substitui o ID; útil para referência cruzada entre bancos/contextos).IActiveState: expõeIsActivepara habilitar/desabilitar sem deletar.ISoftDeletable: expõeIsDeletedpara exclusão lógica.
Referência rápida de API (como Copilot deve sugerir)
- Criar entidade:
public class Product : Entity<Guid> { /* propriedades */ } - Criar DTO associado:
public class ProductDto : IHasId<Guid> { public Guid Id {get;set;} /* ... */ } - Entidade com código:
public class Sku : Entity<int, string> { /* Code já incluído */ }
Quando usar
- Herde de
Entity<TId>para qualquer entidade de domínio com ID. - Use
Entity<TId, TCode>quando existir também um código de negócio único. - Implemente
IHasGuid,IActiveStatee/ouISoftDeletableconforme os requisitos do domínio.
Exemplo básico
using RoyalCode.Entities;
public class Person : Entity<int>
{
public string Name { get; set; } = null!;
}Exemplo com Entity<TId, TCode>
using RoyalCode.Entities;
public class CatalogItem : Entity<Guid, string>
{
public string Name { get; set; } = null!;
// Code é herdado e tem set protegido
public CatalogItem(Guid id, string code, string name)
{
Id = id;
Code = code;
Name = name;
}
}Modelagem de Agregados (DDD). Define a raiz do agregado e integra a coleta de eventos de domínio.
Principais tipos
IAggregateRoot/IAggregateRoot<TId>: marca a raiz do agregado e o tipo do ID.AggregateRoot<TId>: base que herda deEntity<TId>e incluiIDomainEventCollection? DomainEvents+ método protegidoAddEvent(IDomainEvent).AggregateRoot<TId, TCode>: versão comCodealém do ID e dos eventos.
Eventos de domínio
AggregateRoot<TId>mantém uma coleção de eventos (DomainEvents).- Use
AddEvent(evt)para registrar eventos quando invariantes do agregado forem alteradas. - O despacho/persistência de eventos é responsabilidade das bibliotecas de infraestrutura; aqui apenas coletamos os eventos.
Exemplo
using RoyalCode.Aggregates;
using RoyalCode.DomainEvents; // IDomainEvent
public sealed class Order : AggregateRoot<Guid>
{
public string Number { get; private set; }
public Order(string number)
{
Id = Guid.NewGuid();
Number = number;
AddEvent(new OrderCreated(Id, Number));
}
}
public record OrderCreated(Guid OrderId, string Number) : IDomainEvent;Exemplo com AggregateRoot<TId, TCode>
using RoyalCode.Aggregates;
using RoyalCode.DomainEvents;
public sealed class ProductAggregate : AggregateRoot<Guid, string>
{
public string Name { get; private set; }
public ProductAggregate(string code, string name)
{
Id = Guid.NewGuid();
Code = code;
Name = name;
AddEvent(new ProductCreated(Id, Code));
}
}
public record ProductCreated(Guid ProductId, string Code) : IDomainEvent;- Mantenha invariantes do agregado dentro da raiz (
AggregateRoot) e dispare eventos comAddEventapós mudanças significativas. - Não exponha
setpúblico paraId/Code; proteja modificações via comportamentos. - Utilize
IHasGuidquando precisar correlacionar a mesma entidade em múltiplos bancos/contextos. - Prefira
ISoftDeletableeIActiveStatepara cenários de (des)ativação e exclusão lógica.
Para integração com persistência, consulte .docs/workcontext.md.