بنقرة واحدة
koan-entity-first
Entity<T> patterns, GUID v7 auto-generation, static methods vs manual repositories
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
القائمة
Entity<T> patterns, GUID v7 auto-generation, static methods vs manual repositories
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
استنادا إلى تصنيف SOC المهني
Auto-registration via KoanAutoRegistrar, minimal Program.cs, "Reference = Intent" pattern
Chat endpoints, embeddings, RAG workflows, vector search
Aggregate boundaries, relationships, lifecycle hooks, value objects
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
| name | koan-entity-first |
| description | Entity<T> patterns, GUID v7 auto-generation, static methods vs manual repositories |
Entity replaces manual repositories. Every entity is self-aware and self-persisting. This pattern eliminates repository boilerplate while maintaining provider transparency.
await entity.Save(), await entity.Remove()await Entity.All(), await Entity.Get(id), await Entity.Query()// Create entity
public class Todo : Entity<Todo>
{
public string Title { get; set; } = "";
public bool Completed { get; set; }
// Id automatically generated as GUID v7 on first access
}
// Save (create or update)
var todo = new Todo { Title = "Buy milk" };
await todo.Save();
// Retrieve by ID
var loaded = await Todo.Get(id);
// Query all
var allTodos = await Todo.All();
// Filter with LINQ
var completed = await Todo.Query(t => t.Completed);
// Remove
await todo.Remove();
// For non-GUID keys: Entity<T, TKey>
public class NumericEntity : Entity<NumericEntity, int>
{
public override int Id { get; set; }
public string Title { get; set; } = "";
}
// Manual key management
var entity = new NumericEntity { Id = 42, Title = "Meaningful" };
await entity.Save();
// ✅ EFFICIENT: Single bulk query with IN clause
var ids = new[] { id1, id2, id3, id4 };
var todos = await Todo.Get(ids, ct);
// Result: [Todo?, Todo?, null, Todo?] - preserves order, null for missing
// ❌ INEFFICIENT: N database round-trips
var todos = new List<Todo?>();
foreach (var id in ids)
{
todos.Add(await Todo.Get(id, ct)); // N queries!
}
Use Cases:
Performance: Single query vs N queries = 10-100x faster for typical datasets
// Bulk save - efficient provider-specific batching
var todos = Enumerable.Range(0, 1000)
.Select(i => new Todo { Title = $"Task {i}" })
.ToList();
await todos.Save();
// Batch operations — returns IBatchSet<Todo, Guid>, committed with SaveAsync()
// Atomicity: relational providers wrap all operations in a transaction;
// document providers (Mongo) execute sequentially (no distributed tx by default).
// Size guidance: keep batches under ~1 000 items to stay within provider and memory limits.
IBatchSet<Todo, Guid> batch = Todo.Batch();
await batch
.Add(new Todo { Title = "New task" })
.Update(existingId, todo => todo.Completed = true)
.Delete(oldId)
.SaveAsync();
// Basic pagination
var page = await Todo.Page(pageNumber: 1, pageSize: 20);
// With total count for UI
var result = await Todo.QueryWithCount(
t => t.ProjectId == projectId,
new DataQueryOptions(
orderBy: nameof(Todo.Created),
descending: true
),
ct);
Console.WriteLine($"Showing {result.Items.Count} of {result.TotalCount}");
// Stream to avoid loading everything into memory
await foreach (var todo in Todo.AllStream(batchSize: 1000, ct))
{
// Process in batches - memory-efficient
await ProcessTodo(todo);
}
// Stream with filter
await foreach (var reading in Reading.QueryStream(
"plot == 'A1'",
batchSize: 200,
ct))
{
await ProcessReading(reading);
}
When to Stream: Large datasets (>10k records), background jobs, ETL pipelines
Entities can declare [Timestamp] properties for automatic time tracking:
[Timestamp] — set once (creation time)[Timestamp(OnSave = true)] — refreshed on every saveWorks with batch operations (UpsertMany) — all entities in the batch receive the current timestamp.
// DON'T create repository interfaces
public interface ITodoRepository
{
Task<Todo> GetAsync(string id);
Task SaveAsync(Todo todo);
Task<List<Todo>> GetAllAsync();
}
// DON'T inject repositories
public class TodoService
{
private readonly ITodoRepository _repo; // Unnecessary!
public TodoService(ITodoRepository repo) => _repo = repo;
}
Why wrong? Entity already provides all repository functionality. Manual repositories:
// Business logic services use Entity<T> directly
public class TodoService
{
public async Task<Todo> CompleteAsync(string id)
{
var todo = await Todo.Get(id); // Direct entity usage
if (todo is null)
throw new InvalidOperationException("Todo not found");
todo.Completed = true;
return await todo.Save(); // Instance save method
}
public async Task<List<Todo>> GetCompletedAsync()
{
return await Todo.Query(t => t.Completed); // Static query
}
}
Invoke this skill when:
// Default: framework chooses best strategy (usually optimized)
var total = await Todo.Count;
// Explicit exact count (guaranteed accuracy, may be slower)
var exact = await Todo.Count.Exact(ct);
// Explicit fast count (metadata estimate, extremely fast)
var fast = await Todo.Count.Fast(ct);
// Filtered count
var completed = await Todo.Count.Where(t => t.Completed);
Performance: Fast counts use database metadata (1000-20000x faster on large tables)
pg_stat_user_tables (~5ms vs 25s for 10M rows)sys.dm_db_partition_stats (~1ms vs 20s)estimatedDocumentCount() (~10ms vs 15s)When to Use:
examples/entity-crud.cs - Complete CRUD patternsexamples/entity-relationships.cs - Navigation helpersexamples/batch-operations.cs - Bulk loading and savinganti-patterns/manual-repositories.md - What NOT to do with detailed explanationsdocs/guides/entity-capabilities-howto.mddocs/guides/data-modeling.mdsamples/S1.Web/ (Relationship patterns)samples/S0.ConsoleJsonRepo/ (Minimal 20-line example)Entity patterns are mandatory in Koan Framework. Manual repositories break:
Always prefer Entity patterns over custom data access abstractions.