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

2.9 KiB

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, Orderplain 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.OrdersClientDto.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)