Skip to content

Commit

Permalink
Merge pull request #559 from leancodepl/docs/aggregates
Browse files Browse the repository at this point in the history
Add aggregates doc page
  • Loading branch information
michal12334 authored Sep 12, 2023
2 parents b6c4015 + 52e1b22 commit fb61a2d
Show file tree
Hide file tree
Showing 2 changed files with 72 additions and 1 deletion.
70 changes: 70 additions & 0 deletions docs/domain/03_aggregates.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# Aggregates

Aggregates are part of DDD. To create one you have to create a class inheriting [`IAggregateRoot`](../../src/Domain/LeanCode.DomainModels/Model/IAggregateRoot.cs) or [`IAggregateRootWithoutOptimisticConcurrency`](../../src/Domain/LeanCode.DomainModels/Model/IAggregateRoot.cs).

## [`IAggregateRoot`](../../src/Domain/LeanCode.DomainModels/Model/IAggregateRoot.cs)

[`IAggregateRoot`](../../src/Domain/LeanCode.DomainModels/Model/IAggregateRoot.cs) requires you to specify Id type. [`IAggregateRoot`](../../src/Domain/LeanCode.DomainModels/Model/IAggregateRoot.cs) has `Id`, because aggregate root is entity and entities have Ids.

Consider the following aggregate.

```csharp
[TypedId(TypedIdFormat.RawInt)]
public readonly partial record struct UserId;

public class User : IAggregateRoot<UserId>
{
public UserId Id { get; private init; }
public string Name { get; private init; } = null!;

DateTime IOptimisticConcurrency.DateModified { get; set; }

private User()
{ }

public User(UserId id, string name)
{
Id = id;
Name = name;
}
}
```

### Parameterless constructor

Parameterless constructor is required by EntityFramework. It is private because it should not be used in other scenarios, especially application code.

### Id

[`IAggregateRoot`](../../src/Domain/LeanCode.DomainModels/Model/IAggregateRoot.cs) requires you to specify identity type. Every aggregate has an `Id` property of the specified type. We recommend using source-generated Ids as Id types.

### `IOptimisticConcurrency.DateModified`

`DateModified` is optimistic concurrency token managed by application code. It is managed by [`EFRepository`](../../src/Domain/LeanCode.DomainModels.EF/EFRepository.cs) and you shouldn't do it by yourself. It is written this way, instead of `public DateTime DateModified { get; set; }`, to make it not accessible outside [`EFRepository`](../../src/Domain/LeanCode.DomainModels.EF/EFRepository.cs).

## [`IAggregateRootWithoutOptimisticConcurrency`](../../src/Domain/LeanCode.DomainModels/Model/IAggregateRoot.cs)

If you don't want to use optimistic concurrency for your aggregate, you can use [`IAggregateRootWithoutOptimisticConcurrency`](../../src/Domain/LeanCode.DomainModels/Model/IAggregateRoot.cs) instead.

Consider aggregate from previous example, but without optimistic concurrency.

```csharp
public class User : IAggregateRootWithoutOptimisticConcurrency<UserId>
{
public UserId Id { get; private init; }
public string Name { get; private init; } = null!;

private User()
{ }

public User(UserId id, string name)
{
Id = id;
Name = name;
}
}
```

## More

If you want to read more about writing aggregates, you can do that [here](../guides/01_creating_an_aggregate.md).
3 changes: 2 additions & 1 deletion docs/domain/README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# Domain

1. [Value objects](../adrs/2021-02-04_value_object.md),
2. [IDs](./ids.md).
2. [IDs](./ids.md),
3. [Aggregates](./03_aggregates.md).

0 comments on commit fb61a2d

Please sign in to comment.