What is an Aggregate?
An aggregate is a cluster of domain objects treated as a single unit for data changes. It has a root entity that controls all access to the cluster.
Aggregate Root
public class Order : AggregateRoot
{
private readonly List<OrderLine> _lines = [];
public IReadOnlyList<OrderLine> Lines => _lines.AsReadOnly();
public OrderStatus Status { get; private set; }
public void AddLine(Product product, int qty)
{
if (Status != OrderStatus.Draft)
throw new DomainException("Cannot modify a confirmed order.");
_lines.Add(new OrderLine(product.Id, product.Price, qty));
AddDomainEvent(new OrderLineAdded(Id, product.Id, qty));
}
}
Value Objects
public record Money(decimal Amount, string Currency)
{
public Money Add(Money other)
{
if (Currency != other.Currency) throw new InvalidOperationException();
return this with { Amount = Amount + other.Amount };
}
}
💡
Keep aggregates small. An aggregate that loads 500 related objects to perform a simple operation is a design smell. Split it.
Domain Events
public class OrderConfirmed(Guid orderId) : IDomainEvent
{
public Guid OrderId { get; } = orderId;
public DateTime OccurredAt { get; } = DateTime.UtcNow;
}