Skill 10 - EF Core Data Access
Core Concepts
- EF Core maps entity classes to relational database tables.
DbContext represents a unit of work and change tracker.
- Providers translate LINQ expressions to database-specific SQL.
- Database First starts from an existing database; Code First starts from C# models and migrations.
DbContext Rules
- Register
DbContext with dependency injection using an appropriate lifetime, usually scoped for web apps.
- Keep
DbContext short-lived.
- Do not share a
DbContext across threads.
- Use
AsNoTracking() for read-only queries when tracking is not needed.
- Use transactions when multiple changes must succeed or fail together.
Entity Design Rules
- Entities should protect important invariants, but EF also needs materialization support.
- Avoid exposing EF entities directly from public APIs.
- Keep navigation properties intentional.
- Avoid lazy-loading surprises unless the project deliberately uses lazy loading.
Query Rules
- Filter in the database, not in memory.
- Project only needed columns for read models and API responses.
- Watch for N+1 query problems.
- Use
Include intentionally; do not include entire object graphs by habit.
- Use pagination for large result sets.
- Use async EF methods in web applications.
Change Rules
- Validate input before attaching or saving entities.
- Handle concurrency where concurrent updates are possible.
- Do not build SQL by string concatenation with untrusted input.
- Use migrations deliberately and review generated migrations.
Testing Rules
- Use real providers for integration tests where SQL translation matters.
- Avoid assuming the in-memory provider behaves like a relational database.
Repository Pattern
When the project uses a Unit of Work or generic repository abstraction, load .ai/skills/18-unit-of-work-pattern.md for rules on shared DbContext lifetime, repository staging, and single SaveChangesAsync per logical operation.