persistence records carry data: ClientData/OrderData + domain->persistence mappers

The fake DbContext now stores data-only DbBase subclasses (renamed from
the identity-only Shadow wrappers) and refreshes rows in place on re-Save;
the object graph is flattened to ids in storage.

yak: data-carrying-persistence-records-orderdataclientdata-mappers-tb3a
This commit is contained in:
2026-09-16 18:38:38 +01:00
parent 9895ef87e4
commit 49f4ca395f
4 changed files with 215 additions and 65 deletions
+40 -4
View File
@@ -1,13 +1,21 @@
namespace After;
/// <summary>
/// Hand-written mappers between the plain domain and the DTOs (no AutoMapper —
/// the mapping code is part of the illustration). Each public method maps in
/// exactly one direction and never mutates its input.
/// Hand-written mappers out of the plain domain (no AutoMapper — the mapping
/// code is part of the illustration). Each public method maps in exactly one
/// direction and never mutates its input. Two families, two destinations:
/// <list type="bullet">
/// <item><see cref="ClientDto"/>/<see cref="OrderDto"/> — transport to the
/// WebApp;</item>
/// <item><see cref="ClientData"/>/<see cref="OrderData"/> — the data-only
/// records the persistence framework stores.</item>
/// </list>
///
/// The <c>Client.Orders</c> / <c>Order.Client</c> back-reference cycle is
/// resolved with a reference-identity cache: the same instance maps to the
/// same DTO (and back), so the graph terminates and stays consistent.
/// same DTO (and back), so the graph terminates and stays consistent. The
/// persistence mapping needs no cache: records reference each other by id,
/// not by object, so the graph is flattened and cannot cycle.
/// </summary>
public static class Mappers
{
@@ -99,4 +107,32 @@ public static class Mappers
seen[dto] = order;
return order;
}
// ------------------------------------------------------------------
// Domain -> persistence (data-only records; graph flattened to ids)
// ------------------------------------------------------------------
/// <summary>Map a <see cref="Client"/> to its persistence record <see cref="ClientData"/>.</summary>
public static ClientData ToClientData(Client client)
{
ArgumentNullException.ThrowIfNull(client);
return new ClientData { Id = client.Id, Name = client.Name };
}
/// <summary>
/// Map an <see cref="Order"/> to its persistence record <see cref="OrderData"/>:
/// the object graph is flattened — <see cref="Order.Client"/> becomes the
/// <see cref="OrderData.ClientId"/> foreign key (empty when the order has
/// no client, or when that client has not been saved yet).
/// </summary>
public static OrderData ToOrderData(Order order)
{
ArgumentNullException.ThrowIfNull(order);
return new OrderData
{
Id = order.Id,
Description = order.Description,
ClientId = order.Client?.Id ?? Guid.Empty,
};
}
}