Files
db-subclass-to-dto/yak/yak-02-after.md
T

62 lines
2.9 KiB
Markdown

# Yak 02 — C# solution: the AFTER situation (plain domain + DTOs + mappers)
## Context
Depends on Yak 01 (solution, `Before/` project, test project already exist).
Implement the "after" half of the exercise in the existing `After/` project
and add tests. See `after-dto.mmd` for the diagram:
- `Client`, `Order`**plain** domain objects, no `DbBase` inheritance,
no knowledge of `DbContext`
- `ClientDto`, `OrderDto` — DTOs carrying the same data **including the
relations** (`ClientDto.Orders`, back-references)
- `Mappers` — hand-written mapping, each way:
`ToClientDto`, `FromClientDto`, `ToOrderDto`, `FromOrderDto`
- `DbContext`/`DbBase` — still exist (persistence layer), but the domain no
longer subclasses/leaks them
- `WebApp` — consumes **only DTOs**
## Rules
- Do NOT modify `Before/` (it's the frozen "before" state).
- Hand-write the mappers (no AutoMapper) — the mapping code is part of the
illustration. Mappers must not mutate their inputs.
- Keep the fake `DbContext`/`DbBase` for persistence in `After/` (or reuse the
idea from `Before/`), but the domain types must not derive from `DbBase`.
Persisting a domain object now requires explicit registration (e.g. a
`DbContext.Save(client)` that copies into a tracked entity, or registers an
adapter) — the direction of dependency is flipped.
## Required tests (AfterTests)
At minimum, mirroring the Before tests where meaningful:
1. `Client`/`Order` do **not** derive from `DbBase`, and (via reflection)
expose no `DbContext`-typed property or field — the leak is gone.
2. Mappers map all scalar fields, in both directions
(`Client → ClientDto`, `ClientDto → Client`, same for `Order`).
3. Mappers map the relations: `Client.Orders``ClientDto.Orders`, and the
`Order.Client` / `OrderDto.ClientDto` back-references stay consistent.
4. Round-trip: `FromX(ToX(domain))` equals the original domain state
(compare by values, not reference); same for DTO round-trip.
5. Mappers do not mutate their input (snapshot fields, map, compare).
6. `WebApp` (after version) methods consume only `ClientDto`/`OrderDto`;
assert the `After.WebApp` type references no domain or DbContext type in
its public API (reflection over member signatures).
7. Persistence still works through the fake `DbContext` in the after world.
## Acceptance criteria
- `dotnet build` and `dotnet test` succeed on the full solution
(Before + After + tests), 0 warnings.
- No NuGet packages beyond xUnit's default set.
- `Before/` project unmodified (diff check).
- Committed with a message referencing this yak.
## Open questions (answer before starting, defaults in parens)
1. How should the after-world persistence flip look — explicit
`ctx.Save(domainObject)` with internal entity/DTO translation, or something
else? (explicit Save with translation, minimal)
2. Are DTOs records (value equality helps round-trip tests) or plain classes?
(records)