Domain-Driven Design - Aggregate Roots in C#
Before you look at the Aggregate Roots example in C#, you can see at my post on what Aggregate Roots are in Domain-Driven Design.
Aggregate Root interface in C#
public interface IAggregateRoot : IEntity
{
IReadOnlyList<IDomainEvent> DomainEvents { get; }
void AddDomainEvent(IDomainEvent domainEvent);
void ClearDomainEvents();
}
About this code snippet:
- It inherits from
IEntity
(You can found it in this post: Entities in Domain-Driven Design).
Aggregate Root base class in C#
public abstract class AggregateRoot : Entity, IAggregateRoot
{
private readonly List<IDomainEvent> _domainEvents = new List<IDomainEvent>();
public IReadOnlyList<IDomainEvent> DomainEvents
{
get => this._domainEvents.AsReadOnly();
}
protected AggregateRoot() { }
protected AggregateRoot(Guid id) : base(id) { }
public void AddDomainEvent(IDomainEvent domainEvent)
{
this._domainEvents.Add(domainEvent);
}
public void ClearDomainEvents()
{
this._domainEvents.Clear();
}
}
About this code snippet:
- It is an
abstract
class: This prevents this class from being instantiated and allows to declare abstract methods.
Aggregate Root example in C#
public sealed class User : AggregateRoot
{
public FirstName FirstName { get; private set; }
public LastName LastName { get; private set; }
public BirthDate BirthDate { get; private set; }
private User() { }
private User(Guid id, FirstName firstName, LastName lastName, BirthDate birthDate) : base(id)
{
this.FirstName = firstName;
this.LastName = lastName;
this.BirthDate = birthDate;
}
public static User Create(Guid id, FirstName firstName, LastName lastName, BirthDate birthDate)
{
var user = new User(id, firstName, lastName, birthDate);
user.AddDomainEvent(new UserCreatedDomainEvent(user.Id));
return user;
}
public void UpdateFirstName(FirstName firstName)
{
if (this.FirstName.Equals(firstName))
throw new UpdateFirstNameException();
this.FirstName = firstName;
}
public void UpdateLastName(LastName lastName)
{
if (this.LastName.Equals(lastName))
throw new UpdateLastNameException();
this.LastName = lastName;
}
public void UpdateBirthDate(BirthDate birthDate)
{
if (this.BirthDate.Equals(birthDate))
throw new UpdateBirthDateException();
this.BirthDate = birthDate;
}
}
About this code snippet:
- It is a
sealed
class: Prevent another class from extends from this one. - Their properties are
private set
, so they must be modified inside the same class instance. - No public
constructor
: Other classes cannot create instances of this class, except for nested classes. - To create instances of this Aggregate Root we do not call the constructor directly, but it uses the Static Factory Method pattern instead.
- It have methods to change the value of the entity’s properties.
- If an attempt is made to update a property using the same value, it throws an exception.
Categories
Automation scripting Development tools Front end web development Infrastructure Kubernetes Programming guide Security Software architectureTags
Recent Posts
Restart Kubernetes pods following a schedule using Helm
Restart Kubernetes pods following a schedule using Kubectl
Create an Azure Key Vault with RBAC role assignments using Terraform
Get the download url of the latest GitHub release using Bash
Get the download url of the latest GitHub release using PowerShell