Skip to content

Commit 996dad5

Browse files
authored
✨ 364 Add Vogen for Strongly Typed IDs (#441)
1 parent 89019c2 commit 996dad5

File tree

24 files changed

+106
-59
lines changed

24 files changed

+106
-59
lines changed

docs/adr/20241118-produce-useful-sql-server-exceptions.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,7 @@ Chosen option: "Option 1", because it does what we need and is far better than t
2525

2626
- ✅ Strongly typed exceptions
2727
- ❌ Additional dependency added
28+
29+
## Links
30+
31+
- https://youtube.com/watch?v=QKwZlWvfh-o&si=yVnd5a7CVZaSV_Gr

docs/adr/20241118-replace-automapper-with-manual-mapping.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,3 +49,7 @@ Chosen option: "Option 2 - Manual Mapper", because it reduces the runtime errors
4949
- ✅ Reduced runtime issues due to missing fields or mappings
5050
- ✅ No need to learn a new library
5151
- ❌ More code needed for mapping
52+
53+
## Links
54+
55+
- https://www.youtube.com/watch?v=RsnEZdc3MrE
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
# Use Vogen to simplify strongly typed IDs
2+
3+
- Status: approved
4+
- Deciders: Daniel Mackay
5+
- Date: 2024-11-19
6+
- Tags: ddd, vogen, strongly-typed-ids
7+
8+
Technical Story: https://github.com/SSWConsulting/SSW.CleanArchitecture/issues/364
9+
10+
## Context and Problem Statement
11+
12+
Strongly typed IDs are a great way to combat primitive obsession. However, they can be a bit of a pain to set up especially with EF Core. We want to make it easier to use strongly typed IDs or any simple value objects in our projects.
13+
14+
## Decision Drivers <!-- optional -->
15+
16+
- Simplify usage of strongly typed IDs
17+
18+
## Considered Options
19+
20+
1. Manual Approach
21+
2. Vogen
22+
23+
## Decision Outcome
24+
25+
Chosen option: "Option 2 - Vogen", because configuration, validation, and usage of strongly typed IDs is much simpler (espeicially from the EF Core point of view).
26+
27+
## Pros and Cons of the Options <!-- optional -->
28+
29+
### Option 1 - Manual Approach
30+
31+
- ✅ Avoid additional dependencies
32+
- ❌ Extra EF Core boilerplate needed
33+
- ❌ Not easy to add value object validation with current record-based approach
34+
35+
### Option 2 - Vogen
36+
37+
- ✅ Simple to create and use strongly typed IDs
38+
- ✅ Easy to add value object validation
39+
- ✅ Easy to add EF Core configuration
40+
- ✅ Can be used for any simple value object
41+
- ❌ Extra dependency added
42+
43+
## Links
44+
45+
- https://stevedunn.github.io/Vogen/overview.html
46+
- https://github.com/SteveDunn/Vogen

src/Application/UseCases/Heroes/Commands/UpdateHero/UpdateHeroCommand.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ internal sealed class UpdateHeroCommandHandler(IApplicationDbContext dbContext)
2020
{
2121
public async Task<ErrorOr<Guid>> Handle(UpdateHeroCommand request, CancellationToken cancellationToken)
2222
{
23-
var heroId = new HeroId(request.HeroId);
23+
var heroId = HeroId.From(request.HeroId);
2424
var hero = await dbContext.Heroes
2525
.Include(h => h.Powers)
2626
.FirstOrDefaultAsync(h => h.Id == heroId, cancellationToken);

src/Application/UseCases/Teams/Commands/AddHeroToTeam/AddHeroToTeamCommand.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@ internal sealed class AddHeroToTeamCommandHandler(IApplicationDbContext dbContex
1111
{
1212
public async Task<ErrorOr<Success>> Handle(AddHeroToTeamCommand request, CancellationToken cancellationToken)
1313
{
14-
var teamId = new TeamId(request.TeamId);
15-
var heroId = new HeroId(request.HeroId);
14+
var teamId = TeamId.From(request.TeamId);
15+
var heroId = HeroId.From(request.HeroId);
1616

1717
var team = dbContext.Teams
1818
.WithSpecification(new TeamByIdSpec(teamId))

src/Application/UseCases/Teams/Commands/CompleteMission/CompleteMissionCommand.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ internal sealed class CompleteMissionCommandHandler(IApplicationDbContext dbCont
1010
{
1111
public async Task<ErrorOr<Success>> Handle(CompleteMissionCommand request, CancellationToken cancellationToken)
1212
{
13-
var teamId = new TeamId(request.TeamId);
13+
var teamId = TeamId.From(request.TeamId);
1414
var team = dbContext.Teams
1515
.WithSpecification(new TeamByIdSpec(teamId))
1616
.FirstOrDefault();

src/Application/UseCases/Teams/Commands/ExecuteMission/ExecuteMissionCommand.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ internal sealed class ExecuteMissionCommandHandler(IApplicationDbContext dbConte
1414
{
1515
public async Task<ErrorOr<Success>> Handle(ExecuteMissionCommand request, CancellationToken cancellationToken)
1616
{
17-
var teamId = new TeamId(request.TeamId);
17+
var teamId = TeamId.From(request.TeamId);
1818
var team = dbContext.Teams
1919
.WithSpecification(new TeamByIdSpec(teamId))
2020
.FirstOrDefault();

src/Application/UseCases/Teams/Events/PowerLevelUpdatedEventHandler.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ public async Task Handle(PowerLevelUpdatedEvent notification, CancellationToken
2626
}
2727

2828
var team = dbContext.Teams
29-
.WithSpecification(new TeamByIdSpec(hero.TeamId))
29+
.WithSpecification(new TeamByIdSpec(hero.TeamId.Value))
3030
.FirstOrDefault();
3131

3232
if (team is null)

src/Application/UseCases/Teams/Queries/GetTeam/GetTeamQuery.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ public async Task<ErrorOr<TeamDto>> Handle(
1616
GetTeamQuery request,
1717
CancellationToken cancellationToken)
1818
{
19-
var teamId = new TeamId(request.TeamId);
19+
var teamId = TeamId.From(request.TeamId);
2020

2121
var team = await dbContext.Teams
2222
.Where(t => t.Id == teamId)

src/Domain/Domain.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,6 @@
77
<PackageReference Include="Ardalis.Specification" Version="8.0.0" />
88
<PackageReference Include="ErrorOr" Version="2.0.1" />
99
<PackageReference Include="MediatR.Contracts" Version="2.0.1" />
10+
<PackageReference Include="Vogen" Version="5.0.5" />
1011
</ItemGroup>
1112
</Project>

0 commit comments

Comments
 (0)