From 803580786b7565ab81ef3735dbded85854823922 Mon Sep 17 00:00:00 2001 From: Willem van den Ende Date: Wed, 16 Sep 2026 18:39:48 +0100 Subject: [PATCH] order total: TotalInCents on both Orders, mapped into OrderDto and OrderData yak: ordertotalincents-on-both-sides-dto-mapping-j00p --- src/After/DbContext.cs | 4 ++++ src/After/Mappers.cs | 3 +++ src/After/Order.cs | 7 +++++++ src/After/OrderDto.cs | 3 +++ src/Before.Console/Program.cs | 8 ++++---- src/Before/Order.cs | 6 ++++++ tests/BeforeAfter.Tests/AfterPersistenceTests.cs | 5 ++++- tests/BeforeAfter.Tests/AfterTests.cs | 12 ++++++++---- 8 files changed, 39 insertions(+), 9 deletions(-) diff --git a/src/After/DbContext.cs b/src/After/DbContext.cs index 4380ff1..3651c04 100644 --- a/src/After/DbContext.cs +++ b/src/After/DbContext.cs @@ -29,6 +29,9 @@ public sealed class OrderData : DbBase /// Free-text description of what this order is for. public string Description { get; set; } = string.Empty; + /// Order total in cents of the stored order. + public int TotalInCents { get; set; } + /// /// Foreign key to the owning client: when the /// order has no client, or when its client had no id yet at save time — @@ -101,6 +104,7 @@ public class DbContext { var row = (OrderData)existing; // refresh, keep row identity row.Description = fresh.Description; + row.TotalInCents = fresh.TotalInCents; row.ClientId = fresh.ClientId; return; } diff --git a/src/After/Mappers.cs b/src/After/Mappers.cs index d883b54..520ec01 100644 --- a/src/After/Mappers.cs +++ b/src/After/Mappers.cs @@ -72,6 +72,7 @@ public static class Mappers { Id = order.Id, Description = order.Description, + TotalInCents = order.TotalInCents, ClientDto = order.Client is null ? null : MapClient(order.Client, seen), }; seen[order] = dto; @@ -102,6 +103,7 @@ public static class Mappers { Id = dto.Id, Description = dto.Description, + TotalInCents = dto.TotalInCents, Client = dto.ClientDto is null ? null : UnmapClient(dto.ClientDto, seen), }; seen[dto] = order; @@ -132,6 +134,7 @@ public static class Mappers { Id = order.Id, Description = order.Description, + TotalInCents = order.TotalInCents, ClientId = order.Client?.Id ?? Guid.Empty, }; } diff --git a/src/After/Order.cs b/src/After/Order.cs index 57c29c5..9892c2e 100644 --- a/src/After/Order.cs +++ b/src/After/Order.cs @@ -17,6 +17,13 @@ public class Order /// Free-text description of what this order is for. public string Description { get; set; } = string.Empty; + /// + /// Order total in cents (integer — no floating-point money). A normal + /// attribute: it is persisted in and mapped + /// one-on-one into . + /// + public int TotalInCents { get; set; } + /// /// The client that owns this order. Set automatically by /// when the order is added to diff --git a/src/After/OrderDto.cs b/src/After/OrderDto.cs index 1fd53c6..2771262 100644 --- a/src/After/OrderDto.cs +++ b/src/After/OrderDto.cs @@ -13,6 +13,9 @@ public sealed record OrderDto /// Free-text description of what this order is for. public string Description { get; init; } = string.Empty; + /// Order total in cents of the underlying order. + public int TotalInCents { get; init; } + /// /// Back-reference to the owning client, or null for a bare order /// that has not been added to any client. diff --git a/src/Before.Console/Program.cs b/src/Before.Console/Program.cs index b828ed1..6a8bebd 100644 --- a/src/Before.Console/Program.cs +++ b/src/Before.Console/Program.cs @@ -18,10 +18,10 @@ DbBase.Context = ctx; var jane = new Client { Name = "Jane Doe" }; var bob = new Client { Name = "Bob Smith" }; -jane.Orders.Add(new Order { Description = "Design consultation" }); -jane.Orders.Add(new Order { Description = "Website redesign" }); +jane.Orders.Add(new Order { Description = "Design consultation", TotalInCents = 120_00 }); +jane.Orders.Add(new Order { Description = "Website redesign", TotalInCents = 750_00 }); -bob.Orders.Add(new Order { Description = "Monthly retainer" }); +bob.Orders.Add(new Order { Description = "Monthly retainer", TotalInCents = 85_00 }); // Orders need to be attached too so they get IDs: ctx.Attach(jane.Orders[0]); @@ -38,7 +38,7 @@ foreach (var client in DbBase.Context!.Tracked.OfType()) { Console.WriteLine($"{client.Name} [{client.Id}]"); foreach (var order in client.Orders) - Console.WriteLine($" - order [{order.Id}]: {order.Description}"); + Console.WriteLine($" - order [{order.Id}]: {order.Description} ({order.TotalInCents} cents)"); } // ----- find by name ------------------------------------------------------- diff --git a/src/Before/Order.cs b/src/Before/Order.cs index 721d994..b3c4a69 100644 --- a/src/Before/Order.cs +++ b/src/Before/Order.cs @@ -11,6 +11,12 @@ public class Order : DbBase /// Free-text description of what this order is for. public string Description { get; set; } = string.Empty; + /// + /// Order total in cents (integer — no floating-point money). Part of the + /// persisted state, like every other scalar. + /// + public int TotalInCents { get; set; } + /// /// The client that owns this order. Set automatically by /// when the order is added to diff --git a/tests/BeforeAfter.Tests/AfterPersistenceTests.cs b/tests/BeforeAfter.Tests/AfterPersistenceTests.cs index 00739c6..08d1478 100644 --- a/tests/BeforeAfter.Tests/AfterPersistenceTests.cs +++ b/tests/BeforeAfter.Tests/AfterPersistenceTests.cs @@ -16,7 +16,7 @@ public class AfterPersistenceTests { var db = new DbContext(); var client = new Client { Name = "Acme" }; - var order = new Order { Description = "one" }; + var order = new Order { Description = "one", TotalInCents = 15000 }; client.Orders.Add(order); db.Save(client); @@ -29,6 +29,7 @@ public class AfterPersistenceTests var orderRow = Assert.Single(db.Orders); Assert.Equal(order.Id, orderRow.Id); Assert.Equal("one", orderRow.Description); + Assert.Equal(15000, orderRow.TotalInCents); Assert.Equal(client.Id, orderRow.ClientId); // the graph is flattened to a key } @@ -54,6 +55,7 @@ public class AfterPersistenceTests db.Save(order); order.Description = "one (edited)"; + order.TotalInCents = 9900; client.Name = "Acme GmbH"; db.Save(order); db.Save(client); @@ -62,6 +64,7 @@ public class AfterPersistenceTests var orderRow = Assert.Single(db.Orders); Assert.Equal(order.Id, orderRow.Id); Assert.Equal("one (edited)", orderRow.Description); + Assert.Equal(9900, orderRow.TotalInCents); Assert.Equal(client.Id, orderRow.ClientId); var clientRow = Assert.Single(db.Clients); diff --git a/tests/BeforeAfter.Tests/AfterTests.cs b/tests/BeforeAfter.Tests/AfterTests.cs index 5e6cfa5..5e78e81 100644 --- a/tests/BeforeAfter.Tests/AfterTests.cs +++ b/tests/BeforeAfter.Tests/AfterTests.cs @@ -54,12 +54,13 @@ public class AfterTests public void ToOrderDto_maps_all_scalar_fields() { var id = Guid.NewGuid(); - var order = new Order { Id = id, Description = "one" }; + var order = new Order { Id = id, Description = "one", TotalInCents = 15000 }; var dto = Mappers.ToOrderDto(order); Assert.Equal(id, dto.Id); Assert.Equal("one", dto.Description); + Assert.Equal(15000, dto.TotalInCents); } [Fact] @@ -78,12 +79,13 @@ public class AfterTests public void FromOrderDto_maps_all_scalar_fields() { var id = Guid.NewGuid(); - var dto = new OrderDto { Id = id, Description = "one" }; + var dto = new OrderDto { Id = id, Description = "one", TotalInCents = 15000 }; var order = Mappers.FromOrderDto(dto); Assert.Equal(id, order.Id); Assert.Equal("one", order.Description); + Assert.Equal(15000, order.TotalInCents); } // --------------------------------------------------------------------- @@ -129,7 +131,7 @@ public class AfterTests public void Domain_round_trip_preserves_all_state() { var client = new Client { Id = Guid.NewGuid(), Name = "Acme" }; - var order = new Order { Id = Guid.NewGuid(), Description = "one" }; + var order = new Order { Id = Guid.NewGuid(), Description = "one", TotalInCents = 15000 }; client.Orders.Add(order); var roundTrip = Mappers.FromClientDto(Mappers.ToClientDto(client)); @@ -139,6 +141,7 @@ public class AfterTests var roundTripOrder = Assert.Single(roundTrip.Orders); Assert.Equal(order.Id, roundTripOrder.Id); Assert.Equal(order.Description, roundTripOrder.Description); + Assert.Equal(order.TotalInCents, roundTripOrder.TotalInCents); // The back-reference is still consistent on the reconstructed graph: Assert.Same(roundTrip, roundTripOrder.Client); } @@ -159,6 +162,7 @@ public class AfterTests var roundTripOrder = Assert.Single(roundTrip.Orders); Assert.Equal(dtoOrder.Id, roundTripOrder.Id); Assert.Equal(dtoOrder.Description, roundTripOrder.Description); + Assert.Equal(dtoOrder.TotalInCents, roundTripOrder.TotalInCents); Assert.Same(roundTrip, roundTripOrder.ClientDto); } @@ -244,7 +248,7 @@ public class AfterTests { var app = new WebApp(); var client = new Client { Id = Guid.NewGuid(), Name = "Acme" }; - var order = new Order { Id = Guid.NewGuid(), Description = "order one" }; + var order = new Order { Id = Guid.NewGuid(), Description = "order one", TotalInCents = 15000 }; client.Orders.Add(order); var view = app.ShowClient(Mappers.ToClientDto(client));