# Aggregates

The aggregate ensures that all the changes to the objects within the aggregate are performed in a consistent and transactional manner.<br>

Key characteristics of an Aggregate are:

1. **Consistency Boundary**: The aggregate defines a clear boundary for transactional consistency. All invariants and business rules within an aggregate must be satisfied as a whole, ensuring that the domain remains in a valid state at all times.
2. **Encapsulation**: The internal structure and state of the aggregate's objects are hidden from the outside world. External entities can only interact with the aggregate through its root.
3. **Lifecycle**: Aggregates are typically long-lived, persisting over multiple transactions. They should be designed with consideration for their lifecycle management.
4. **Isolation**: Aggregates should not directly reference or hold references to other aggregates. Instead, they can reference other aggregates by their unique identifiers (IDs).

{% hint style="info" %}
**Eiffel.Modelling.Abstractions** NuGet package contains base aggregate class. By using abstract Aggregate class you can define your aggregates.
{% endhint %}

```csharp
/// <summary>
/// Aggregate implementation
/// </summary>
/// <typeparam name="TIdentity">The type of unique business identifier</typeparam>
/// <typeparam name="TKey">The type of database primary key</typeparam>
public abstract class Aggregate<TIdentity, TKey> : EntityBase<TKey>, IAggregate
   where TIdentity : ValueObject<TIdentity>
   where TKey : struct, IEquatable<TKey>
{
    /// <summary>
    /// Domain events collection
    /// </summary>
    public IReadOnlyCollection<IDomainEvent> DomainEvents => _domainEvents.ToList();
    
    /// <summary>
    /// Business identifier
    /// </summary>
    public abstract TIdentity Identity { get; internal set; }
    
    private readonly List<IDomainEvent> _domainEvents;
    /// <summary>
    /// CTOR
    /// </summary>
    public Aggregate()
    {
        _domainEvents = new List<IDomainEvent>();
    }
    
    /// <summary>
    /// Raises/adds domain event
    /// </summary>
    /// <typeparam name="TEvent">The type of the class representing domain event</typeparam>
    /// <param name="domainEvent">Domain event</param>
    protected void Raise<TEvent>(TEvent domainEvent)
        where TEvent : IDomainEvent
    {
        _domainEvents.Add(domainEvent);
    }
    
    /// <summary>
    /// Clears all domain events
    /// </summary>
    public void ClearEvents()
    {
        _domainEvents.Clear();
    }
}
```

Each Aggregate is likely to contain more than one function and these functions are business needs demanded by domain experts/stakeholders. Each function usually requires notifying other members of the system that an event has occurred. These events are called [Domain Events](/principles/domain-driven-design/domain-events.md). Each Aggregate is responsible for keeping the events occurring within itself.\
\
Each Aggregate must have a uniquely defined identity type and primary key type required for the database. You can find the identity details specific to the aggregates in the [Business Identifiers](/principles/domain-driven-design/business-identifiers.md) section.\
\
\&#xNAN;*Example Booking Aggregate with BookingCancelled domain event.*

```csharp
public class Booking : Aggregate<BookingId, Guid>
{
    // Business identifier
    public override BookingId Identifier { get; private set; }

    // Status enum
    public BookingStatus Status { get; private set; }

    // ...
    // ...
    void Cancel(string reason)
    {
        Status = BookingStatus.Cancelled;
        Raise(new BookingCancelled(BookingId, reason));
    }
}
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.eiffel.dev/principles/domain-driven-design/aggregates.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
