4.3 The models
Data/Models/Product.cs:
using System.ComponentModel.DataAnnotations;
namespace Shopfront.Data.Models;
public class Product
{
public required string Sku { get; set; }
public required string Name { get; set; }
public decimal Price { get; set; }
public int Stock { get; set; }
// Postgres's row version. A save that finds the row changed since it was read is refused.
[Timestamp]
public uint Version { get; set; }
}Two customers can order the last T-shirt at the same moment. Both read a stock of one, both
take one, and both save a stock of zero: one T-shirt sold twice. Version stops that. On Postgres a
uint marked [Timestamp] is the row's system version, xmin, which changes on every write.
Entity Framework adds it to the update's WHERE, so the second save matches no row and is refused
with a DbUpdateConcurrencyException instead of overwriting the first.
Data/Models/Order.cs:
namespace Shopfront.Data.Models;
public class Order
{
public Guid Id { get; set; }
public required string CustomerId { get; set; }
public decimal Total { get; set; }
public required string TransactionId { get; set; }
public DateTime PlacedAt { get; set; }
public List<OrderItem> Items { get; set; } = [];
}Data/Models/OrderItem.cs:
namespace Shopfront.Data.Models;
public class OrderItem
{
public int Id { get; set; }
public Guid OrderId { get; set; }
public required string Sku { get; set; }
public int Quantity { get; set; }
public decimal UnitPrice { get; set; }
}An order keeps the price each item was sold at, so a later change to the catalogue does not rewrite what a customer paid. The receipt link is not stored: the customer has it, and the shop does not need it.
SDK Reference
DomainDataContext | EnsureSchemaCreatedAsync | Add a domain data context | IFailureClassifier | Architecture guards