Interface IAggregate
- Namespace
- Trellis
- Assembly
- Trellis.DomainDrivenDesign.dll
Defines the contract for an aggregate root in Domain-Driven Design. An aggregate is a cluster of domain objects that can be treated as a single unit for data changes.
public interface IAggregate : IChangeTracking
- Inherited Members
- Extension Methods
Examples
public class Order : Aggregate<OrderId>
{
private readonly List<OrderLine> _lines = [];
public Result<Order> AddLine(ProductId productId, int quantity)
{
// Business logic here
DomainEvents.Add(new OrderLineAddedEvent(Id, productId, quantity));
return this;
}
}
Remarks
Aggregates are the primary building blocks of domain models in DDD. Key characteristics:
- Aggregate roots are the only entry point for modifications to the aggregate
- Ensures all business rules and invariants within the aggregate boundary are maintained
- Tracks domain events that occur during state changes
- External objects can only hold references to the aggregate root, not internal entities
This interface combines change tracking (from IChangeTracking) with domain event management.
Properties
ETag
Gets the entity tag (ETag) for optimistic concurrency per RFC 9110.
string ETag { get; }
Property Value
- string
An opaque string token that changes each time the aggregate is persisted. Used by the persistence layer to detect concurrent modifications and by the HTTP layer for conditional requests (
ETag/If-Matchheaders).
Remarks
The ETag is managed automatically by the persistence infrastructure:
- For SQL databases, the EF Core interceptor generates a new GUID on each save
- For CosmosDB, the native
_etagis used directly
Domain code should not modify this property directly.
Methods
UncommittedEvents()
Gets all domain events that have been raised but not yet marked as committed.
IReadOnlyList<IDomainEvent> UncommittedEvents()
Returns
- IReadOnlyList<IDomainEvent>
A read-only list of domain events that occurred during state changes since the last call to AcceptChanges(). Returns an empty list if no uncommitted events exist.
Remarks
Domain events represent significant state changes that have occurred within the aggregate. These events should be:
- Published to an event bus or message broker after successful persistence
- Used to trigger side effects or update read models
- Cleared by calling AcceptChanges() after successful processing
Typical workflow:
// 1. Execute domain operation
var result = order.Submit();
// 2. Save aggregate to repository
await repository.SaveAsync(order);
// 3. Publish uncommitted events
foreach (var evt in order.UncommittedEvents())
{
await eventBus.PublishAsync(evt);
}
// 4. Mark changes as committed
order.AcceptChanges();