Claude-skill-registry koan-entity-first
Entity<T> patterns, GUID v7 auto-generation, static methods vs manual repositories
git clone https://github.com/majiayu000/claude-skill-registry
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/entity-first" ~/.claude/skills/majiayu000-claude-skill-registry-koan-entity-first && rm -rf "$T"
skills/data/entity-first/SKILL.mdKoan Entity-First Development
Core Principle
Entity<T> replaces manual repositories. Every entity is self-aware and self-persisting. This pattern eliminates repository boilerplate while maintaining provider transparency.
Revolutionary Approach
- GUID v7 Auto-Generation: IDs generated automatically with chronological ordering
- Instance Methods:
,await entity.Save()await entity.Remove() - Static Queries:
,await Entity.All()
,await Entity.Get(id)await Entity.Query() - Provider Agnostic: Same code works across SQL, NoSQL, Vector, JSON stores
Quick Reference Card
Basic Operations
// 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();
Custom Keys (When Needed)
// 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();
Batch Operations
Batch Retrieval (Prevents N+1 Queries)
// ✅ 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:
- Collection/playlist pagination - fetch page of items by stored IDs
- Relationship navigation - fetch all related entities at once
- Bulk validation - check which IDs exist in single query
Performance: Single query vs N queries = 10-100x faster for typical datasets
Batch Persistence
// 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 - add/update/delete in one transaction await Todo.Batch() .Add(new Todo { Title = "New task" }) .Update(existingId, todo => todo.Completed = true) .Delete(oldId) .SaveAsync();
Pagination & Streaming
Pagination (Web APIs)
// 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}");
Streaming (Large Datasets)
// 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
Anti-Patterns to Avoid
❌ WRONG: Manual Repository Pattern
// 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<T> already provides all repository functionality. Manual repositories:
- Duplicate framework features
- Break provider transparency
- Add unnecessary abstraction layers
- Increase maintenance burden
✅ CORRECT: Entity Service Pattern
// 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 } }
When This Skill Applies
Invoke this skill when:
- ✅ Creating new entities
- ✅ Adding data access code
- ✅ Refactoring repositories to Entity<T>
- ✅ Building CRUD operations
- ✅ Reviewing data access patterns
- ✅ Troubleshooting entity persistence
- ✅ Optimizing queries (batch operations, streaming)
Advanced: Count Operations
// 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)
- Postgres:
(~5ms vs 25s for 10M rows)pg_stat_user_tables - SQL Server:
(~1ms vs 20s)sys.dm_db_partition_stats - MongoDB:
(~10ms vs 15s)estimatedDocumentCount()
When to Use:
- Fast: Pagination UI, dashboard summaries, estimates acceptable
- Exact: Critical business logic, inventory counts, reports requiring accuracy
Bundled Resources
- Complete CRUD patternsexamples/entity-crud.cs
- Navigation helpersexamples/entity-relationships.cs
- Bulk loading and savingexamples/batch-operations.cs
- What NOT to do with detailed explanationsanti-patterns/manual-repositories.md
Reference Documentation
- Full Guide:
docs/guides/entity-capabilities-howto.md - Data Modeling:
docs/guides/data-modeling.md - ADR: DATA-0059 (Entity-first facade decision)
- Sample:
(Relationship patterns)samples/S1.Web/ - Sample:
(Minimal 20-line example)samples/S0.ConsoleJsonRepo/
Framework Compliance
Entity<T> patterns are mandatory in Koan Framework. Manual repositories break:
- Provider transparency
- Framework auto-registration
- Capability detection
- Multi-tenant context routing
Always prefer Entity<T> patterns over custom data access abstractions.