ワンクリックで
koan-data-modeling
Aggregate boundaries, relationships, lifecycle hooks, value objects
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
メニュー
Aggregate boundaries, relationships, lifecycle hooks, value objects
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
Auto-registration via KoanAutoRegistrar, minimal Program.cs, "Reference = Intent" pattern
Chat endpoints, embeddings, RAG workflows, vector search
Entity<T> patterns, GUID v7 auto-generation, static methods vs manual repositories
Transparent L1/L2 caching for Entity<T>, [Cacheable] attribute, cross-node coherence, per-request opt-out
Run a mandatory pre-implementation exploration workflow before writing production code in Koan (.NET/C#). Use when a task requires code changes and Codex must first map concerns/layers, read relevant files and docs, check existing constants and types, identify the closest existing pattern, plan exact code placement, and confirm architectural guardrails.
EntityController<T>, custom routes, payload transformers, auth policies
SOC 職業分類に基づく
| name | koan-data-modeling |
| description | Aggregate boundaries, relationships, lifecycle hooks, value objects |
Entities are aggregates that encapsulate business logic and define clear boundaries. Use lifecycle hooks for invariants, value objects for cohesive data, and navigation helpers for relationships.
public class Order : Entity<Order>
{
public string CustomerId { get; set; } = "";
public Money Total { get; private set; } = new(0m, "USD");
public OrderStatus Status { get; private set; } = OrderStatus.Draft;
// Business methods
public void MarkShipped() => Status = OrderStatus.Shipped;
// Navigation helper
public Task<Customer?> GetCustomer(CancellationToken ct = default) =>
Customer.Get(CustomerId, ct);
// Domain query
public static Task<List<Order>> RecentOrders(int days = 7, CancellationToken ct = default) =>
Query(o => o.Created > DateTimeOffset.UtcNow.AddDays(-days), ct);
}
public record Money(decimal Amount, string Currency);
public record Address(string Street, string City, string State, string Zip);
public class Invoice : Entity<Invoice>
{
public Money Total { get; set; } = new(0m, "USD");
public Address ShippingAddress { get; set; } = new("", "", "", "");
}
public static class ProductLifecycle
{
public static void Configure(EntityLifecycleBuilder<Product> pipeline)
{
pipeline.ProtectAll()
.Allow(p => p.Price, p => p.Description)
.BeforeUpsert(async (ctx, next) =>
{
if (ctx.Entity.Price < 0)
throw new InvalidOperationException("Price cannot be negative");
await next();
})
.AfterLoad(ctx => ctx.Entity.FormattedPrice = $"${ctx.Entity.Price:F2}");
}
}
public class Todo : Entity<Todo>
{
public string UserId { get; set; } = "";
public string? CategoryId { get; set; }
// Navigation helpers
public Task<User?> GetUser(CancellationToken ct = default) =>
User.Get(UserId, ct);
public Task<Category?> GetCategory(CancellationToken ct = default) =>
string.IsNullOrEmpty(CategoryId) ? Task.FromResult<Category?>(null)
: Category.Get(CategoryId, ct);
public Task<List<TodoItem>> GetItems(CancellationToken ct = default) =>
TodoItem.Query(i => i.TodoId == Id, ct);
}
Use [Timestamp] to auto-manage creation and modification times:
public class Order : Entity<Order>
{
public string CustomerId { get; set; } = "";
public decimal Total { get; set; }
[Timestamp] // Set once on first save
public DateTimeOffset CreatedAt { get; set; }
[Timestamp(OnSave = true)] // Updated on every save
public DateTimeOffset UpdatedAt { get; set; }
}
No manual assignment needed — the framework's lifecycle hooks handle it via compiled expression trees for zero-overhead hot-path performance.
docs/guides/data-modeling.mddocs/examples/entity-pattern-recipes.mdsamples/S1.Web/ (Relationship patterns)