diff --git a/.agents/skills/analyzers/SKILL.md b/.agents/skills/analyzers/SKILL.md new file mode 100644 index 00000000000..8efbb40967e --- /dev/null +++ b/.agents/skills/analyzers/SKILL.md @@ -0,0 +1,5 @@ +--- +name: analyzers +description: 'Implementation details for EF Core Roslyn analyzers. Use when changing analyzers, fix providers, or diagnostic suppressors.' +user-invokable: false +--- \ No newline at end of file diff --git a/.agents/skills/bulk-operations/SKILL.md b/.agents/skills/bulk-operations/SKILL.md new file mode 100644 index 00000000000..32b2a97b891 --- /dev/null +++ b/.agents/skills/bulk-operations/SKILL.md @@ -0,0 +1,5 @@ +--- +name: bulk-operations +description: 'Implementation details for EF Core ExecuteUpdate/ExecuteDelete bulk operations. Use when changing UpdateExpression/DeleteExpression LINQ translation or the corresponding SQL AST nodes.' +user-invokable: false +--- diff --git a/.agents/skills/change-tracking/SKILL.md b/.agents/skills/change-tracking/SKILL.md new file mode 100644 index 00000000000..71a6f98659a --- /dev/null +++ b/.agents/skills/change-tracking/SKILL.md @@ -0,0 +1,32 @@ +--- +name: change-tracking +description: 'Implementation details for EF Core change tracking. Use when changing InternalEntityEntry, ChangeDetector, SnapshotFactoryFactory, or related entity state, snapshot, or property accessor code.' +user-invokable: false +--- + +# Change Tracking + +Manages entity states and detects changes for `SaveChanges()`. + +## Core Components + +- `StateManager` — central engine, identity maps, tracks all entities +- `InternalEntityEntry` — per-entity state, property flags, snapshots +- `SnapshotFactoryFactory` subclasses build snapshot factories for change detection +- `PropertyAccessorsFactory`, `ClrPropertyGetterFactory` and `ClrPropertySetterFactory` compile property accessors for efficient snapshotting and change detection + - Ordinals in `indices` parameter specify element at each complex collection depth + +## Testing + +Unit tests: `test/EFCore.Tests/ChangeTracking/`. Functional tests: `test/EFCore.Specification.Tests/GraphUpdates/`. + +## Common Pitfalls + +| Pitfall | Solution | +|---------|----------| +| There is a failure when there is shared identity entry (Added and Deleted) | Add code that checks `SharedIdentityEntry` | + +## Validation + +- `DetectChanges()` identifies modified properties via snapshot comparison +- Setting original values marks properties as modified or unchanged based on comparison with current values diff --git a/.agents/skills/cosmos-provider/SKILL.md b/.agents/skills/cosmos-provider/SKILL.md new file mode 100644 index 00000000000..1b7458dc2de --- /dev/null +++ b/.agents/skills/cosmos-provider/SKILL.md @@ -0,0 +1,22 @@ +--- +name: cosmos-provider +description: 'Implementation details for the EF Core Azure Cosmos DB provider. Use when changing Cosmos-specific code.' +user-invokable: false +--- + +# Cosmos DB Provider + +Non-relational provider with its own parallel query pipeline. Uses JSON for document materialization. + +## When to Use + +- Working on Cosmos SQL generation +- Working on document storage, partition key configuration, or `CosmosClientWrapper` + +## Key Differences from Relational + +- No migrations — use `EnsureCreated()` +- Documents as JSON — owned and complex types become embedded objects +- Partition key configuration required for performance +- `ETag` for optimistic concurrency +- No cross-container joins diff --git a/.agents/skills/create-custom-agent/SKILL.md b/.agents/skills/create-custom-agent/SKILL.md new file mode 100644 index 00000000000..183fa114a6d --- /dev/null +++ b/.agents/skills/create-custom-agent/SKILL.md @@ -0,0 +1,246 @@ +--- +name: create-custom-agent +description: 'Create custom GitHub Copilot agents. Use when asked to create, scaffold, or configure a custom agent, declarative agent, or @-invokable chat participant for GitHub Copilot.' +--- + +# Create Custom Agent + +This skill guides you through creating a custom GitHub Copilot agent — an `@`-invokable chat participant that extends Copilot with domain-specific expertise. Custom agents are distinct from Agent Skills: skills provide reusable instructions loaded on demand, while agents own the full conversational interaction and can orchestrate tools, call APIs, and maintain their own prompt strategies. + +## When Not to Use + +- Adding reusable, invokable workflows — use Agent Skills (`.agents/skills/`) instead +- Adding background coding guidelines — use file-based instructions (`.github/instructions/`) instead +- Adding project-wide context for Copilot — use `.github/copilot-instructions.md` instead +- Creating reusable prompts — use .prompt.md instead + +## Workflow + +### Step 1: Choose the agent type + +| Type | Location | Best for | +|---|---|---| +| Declarative (prompt file) | `.github/agents/.md` | Simple prompt-driven cross-surface agents with no code | +| Extension-based (chat participant) | VS Code extension project | Full control, tool calling, VS Code API access | +| GitHub App (Copilot Extension) | Hosted service + GitHub App | Cross-surface agents (github.com, VS Code, Visual Studio) | + +If the agent only needs a scoped system prompt and doesn't require custom code, start with a declarative agent. + +### Step 2: Create a declarative agent (prompt file) + +Declarative agents are Markdown files in `.github/agents/`. VS Code and GitHub Copilot discover them automatically. + +``` +.github/agents/ +└── .md # Agent definition +``` + +Template: + +```markdown +--- +name: my-agent +description: A short description of what this agent does and when to use it. +--- + +# + +You are an expert in . Your job is to: +- +- + +## Guidelines + +- +- + +## Workflow + +1. +2. + +## Constraints + +- +- + +``` + +Supported frontmatter fields: + +| Field | Required | Description | +|---|---|---| +| `name` | Yes | Lowercase, hyphens allowed. Used for `@`-mention. | +| `description` | Yes | What the agent does and when to use it. Shown in the participant list. | +| `target` | No | Target environment: `vscode` or `github-copilot` (defaults to both) | +| `tools` | No | List of allowed tools/tool sets | +| `model` | No | LLM name or prioritized array of models | +| `user-invokable` | No | Show in agents dropdown (default: true) | +| `disable-model-invocation` | No | Prevent subagent invocation (default: false) | +| `mcp-servers` | No | MCP server configs for GitHub Copilot target | +| `metadata` | No | Key-value mapping for additional arbitrary metadata. | +| `argument-hint` | No | Hint text guiding user interaction (VS Code only) | +| `agents` | No | List of allowed subagents (`*` for all, `[]` for none, VS Code only) | +| `handoffs` | No | List of next-step agent transitions (VS Code only) | + + +Tips for instructions: +- Use Markdown links to reference other files +- Reference tools with `#tool:` syntax +- Be specific about agent behavior and constraints + +### Step 3: Configure tools + +Specify which tools the agent can use: + +```yaml +tools: + - search # Built-in tool + - fetch # Built-in tool + - codebase # Tool set + - myServer/* # All tools from MCP server +``` + +Common tool patterns: +- **Read-only agents**: `['search', 'fetch', 'codebase']` +- **Full editing agents**: `['*']` or specific editing tools +- **Specialized agents**: Cherry-pick specific tools + +### Step 4: Add handoffs (optional, VS Code only) + +Configure transitions to other agents: + +```yaml +handoffs: + - label: Start Implementation + agent: implementation + prompt: Implement the plan outlined above. + send: false + model: GPT-5.2 (copilot) +``` + +Handoff fields: +- `label`: Button text displayed to user +- `agent`: Target agent identifier +- `prompt`: Pre-filled prompt for target agent +- `send`: Auto-submit prompt (default: false) +- `model`: Optional model override for handoff + +### Step 5: Create an extension-based chat participant (VS Code only) + +For full control, implement a VS Code extension with a chat participant: + +1. **Define the participant** in `package.json`: + +```json +"contributes": { + "chatParticipants": [ + { + "id": "my-extension.my-agent", + "name": "my-agent", + "fullName": "My Agent", + "description": "Short description shown in chat input", + "isSticky": false, + "commands": [ + { + "name": "explain", + "description": "Explain the selected code" + } + ] + } + ] +} +``` + +2. **Register and implement the request handler** in `extension.ts`: + +```typescript +export function activate(context: vscode.ExtensionContext) { + const agent = vscode.chat.createChatParticipant('my-extension.my-agent', handler); + agent.iconPath = vscode.Uri.joinPath(context.extensionUri, 'icon.png'); +} + +const handler: vscode.ChatRequestHandler = async ( + request: vscode.ChatRequest, + context: vscode.ChatContext, + stream: vscode.ChatResponseStream, + token: vscode.CancellationToken +) => { + const model = request.model; + const messages = [ + vscode.LanguageModelChatMessage.User(request.prompt) + ]; + const response = await model.sendRequest(messages, {}, token); + for await (const fragment of response.text) { + stream.markdown(fragment); + } +}; +``` + +3. **Declare the extension dependency** in `package.json`: + +```json +"extensionDependencies": ["github.copilot-chat"] +``` + +4. **Add tool calling (optional)** + +Agents can invoke language model tools registered by other extensions: + +```typescript +const tools = vscode.lm.tools.filter(tool => tool.tags.includes('my-domain')); +const result = await chatUtils.sendChatParticipantRequest(request, context, { + prompt: 'You are an expert in .', + tools, + responseStreamOptions: { stream, references: true, responseText: true } +}, token); +return await result.result; +``` + +### Step 6: Create a GitHub App (Copilot Extension) for cross-surface availability (optional) + +If the agent should be available on GitHub.com, Visual Studio, JetBrains, and VS Code simultaneously, implement a GitHub App that acts as a Copilot Extension. The app registers a webhook endpoint, receives chat requests, and streams responses back. + +Key considerations: +- The GitHub App must be installed on the user's account or organization +- Responses are streamed via Server-Sent Events (SSE) +- Use the [GitHub Copilot Extensions documentation](https://docs.github.com/en/copilot/building-copilot-extensions/about-building-copilot-extensions) for the full integration guide +- For VS Code-specific features (editor access, file trees, command buttons), prefer an extension-based participant instead + +### Step 7: Validate + +After creating or modifying an agent, verify: + +- [ ] `name` is lowercase, uses hyphens (no spaces), and is unique +- [ ] `description` clearly describes what the agent does and when to invoke it +- [ ] Frontmatter YAML is valid (no syntax errors) +- [ ] Declarative agent file is in `.github/agents/` +- [ ] Tools list contains only available tools +- [ ] Extension-based agent: participant ID matches in `package.json` and `createChatParticipant` call +- [ ] Agent does not duplicate functionality of built-in agents (`@workspace`, `@vscode`, `@terminal`) +- [ ] Handoff agent names match existing agents +- [ ] Agent instructions don't include secrets, tokens, or internal URLs + +## Common Pitfalls + +| Pitfall | Solution | +|---------|----------| +| Agent name conflicts with built-in participants | Use a unique prefix (domain name) | +| Description is too vague | Include specific keywords users would naturally say | +| System prompt is too long | Keep instructions to essential behaviors; move reference material to Agent Skills | +| Agent requires VS Code API but is authored as declarative | Switch to extension-based participant | +| Using `isSticky: true` unnecessarily | Only set sticky if the agent should persist between turns by default | +| No `extensionDependencies` on `github.copilot-chat` | Add it; otherwise the contribution point may not be available | +| Agent invoked as subagent unexpectedly | Set `disable-model-invocation: true` | +| Subagent appears in the dropdown | Set `user-invokable: false` | + +## References + +- [VS Code Chat Participant API](https://code.visualstudio.com/api/extension-guides/ai/chat) +- [VS Code AI Extensibility Overview](https://code.visualstudio.com/api/extension-guides/ai/ai-extensibility-overview) +- [VS Code Extension Samples – chat-sample](https://github.com/microsoft/vscode-extension-samples/tree/main/chat-sample) +- [GitHub Copilot Extensions documentation](https://docs.github.com/en/copilot/building-copilot-extensions/about-building-copilot-extensions) +- [GitHub Copilot Custom agents configuration](https://docs.github.com/en/copilot/reference/custom-agents-configuration) +- [Agent Skills Specification](https://agentskills.io/specification) +- [make-skill](../make-skill/SKILL.md) +- [make-instructions](../make-instructions/SKILL.md) diff --git a/.agents/skills/dbcontext-and-services/SKILL.md b/.agents/skills/dbcontext-and-services/SKILL.md new file mode 100644 index 00000000000..638d33819bf --- /dev/null +++ b/.agents/skills/dbcontext-and-services/SKILL.md @@ -0,0 +1,20 @@ +--- +name: dbcontext-and-services +description: 'Implementation details for EF Core DbContext and the DI service infrastructure. Use when changing context configuration, service registration, service lifetimes, DbContext pooling, or the Dependencies pattern.' +user-invokable: false +--- + +# DbContext & Services + +EF Core's internal DI container, service registration, and context lifecycle management. + +## Service Registration + +`EntityFrameworkServicesBuilder` maintains a `CoreServices` dictionary mapping service types to `ServiceCharacteristics` (lifetime + multi-registration flag). + +## Dependencies Pattern + +Services receive dependencies via sealed records (not constructor injection of individual services): +```csharp +public sealed record MyServiceDependencies(IDep1 Dep1, IDep2 Dep2); +``` diff --git a/.agents/skills/make-instructions/SKILL.md b/.agents/skills/make-instructions/SKILL.md new file mode 100644 index 00000000000..551dc3eddd6 --- /dev/null +++ b/.agents/skills/make-instructions/SKILL.md @@ -0,0 +1,94 @@ +--- +name: make-instructions +description: 'Create VS Code file-based instructions (.instructions.md files). Use when asked to create, scaffold, or add file-based instructions for Copilot. Generates .instructions.md with YAML frontmatter and background knowledge content.' +--- + +# Create File-Based Instructions + +This skill helps you scaffold VS Code file-based instructions (`.instructions.md` files) that provide background knowledge to Copilot about specific parts of the codebase. These files are applied automatically based on glob patterns or semantic matching, giving Copilot domain-specific context when working on matching files. + +## When Not to Use + +- Setting project-wide instructions — use `.github/copilot-instructions.md` or `AGENTS.md` instead +- Creating reusable agent workflows with structured steps — use Agent Skills instead +- Adding instructions that need to be invokable on demand — use Agent Skills instead + +## Workflow + +### Step 1: Investigate the topic + +Build understanding of the area the instructions should cover. Identify: + +- [ ] What files or file patterns the instructions apply to +- [ ] Key conventions, patterns, or architectural rules for that area +- [ ] Common pitfalls that Copilot should avoid +- [ ] Non-obvious domain knowledge that isn't discoverable from code alone + +If the scope is unclear or overlaps with existing instructions, ask the user for clarification. + +### Step 2: Choose the file location + +Instructions files go in `.github/instructions/` by default. Pick a descriptive filename: + +``` +.github/instructions/.instructions.md +``` + +Examples: `csharp-style.instructions.md`, `query-pipeline.instructions.md`, `test-conventions.instructions.md` + +### Step 3: Generate the file with YAML frontmatter + +Create the file with the required YAML frontmatter header: + +```yaml +--- +name: '' # Optional. Display name in the UI. Defaults to filename. +description: '' # Optional. Shown on hover. Also used for semantic matching. +applyTo: '' # Optional. Glob pattern relative to workspace root. Omit to require manual attachment or rely on semantic matching only. +--- +``` + +Common `applyTo` patterns: + +- `**/*.cs` — all C# files +- `test/**` — files under a specific folder + +### Step 4: Write the body content + +Write concise, actionable Markdown content. Follow these principles: + +- **Be concise** — instructions share the context window; only include what the agent wouldn't already know +- **Be specific** — use concrete rules, not vague guidance +- **Include examples** — short code snippets showing preferred vs. avoided patterns are very effective +- **Explain why** — when a rule exists for a non-obvious reason, state it so the agent applies it correctly in edge cases +- **Skip linter-enforced rules** — don't repeat what formatters and linters already catch +- **Use Markdown links** to reference specific files or URLs for additional context + +Recommended sections (adapt as needed): + +1. **** — one-line heading describing the domain +2. **Context paragraph** — brief explanation of what this area is and why these rules matter +3. **Guidelines / Conventions** — bullet list of concrete rules +4. **Examples** — short code blocks showing do/don't patterns (optional) +5. **Key Files** — table of important files for orientation (optional) +6. **Common Pitfalls** — traps to avoid (optional) + +### Step 5: Validate + +After creating the file, verify: + +- [ ] File is in `.github/instructions/` (or a configured instructions folder) +- [ ] Filename ends with `.instructions.md` and only contains lowercase letters, numbers, and hyphens +- [ ] YAML frontmatter is valid +- [ ] `applyTo` glob matches the intended files +- [ ] Content is concise (aim for under 500 lines or 5000 tokens) — long instructions dilute effectiveness +- [ ] No secrets, tokens, or internal URLs included +- [ ] Instructions don't duplicate what's already in `.github/copilot-instructions.md` or under `.agents/skills/` + +## Common Pitfalls + +| Pitfall | Solution | +|---------|----------| +| `applyTo` too broad | Use specific globs; `**` applies to every file and wastes context | +| Missing `applyTo` | Without it, instructions won't auto-apply — they require manual attachment or semantic matching via `description` | +| Vague guidance | Replace "write good tests" with something like "add both positive and negative test cases using `[ConditionalFact]` methods" | diff --git a/.agents/skills/make-skill/SKILL.md b/.agents/skills/make-skill/SKILL.md new file mode 100644 index 00000000000..f519d981ea0 --- /dev/null +++ b/.agents/skills/make-skill/SKILL.md @@ -0,0 +1,121 @@ +--- +name: make-skill +description: 'Create new Agent Skills for GitHub Copilot. Use when asked to create, scaffold, or add a skill. Generates SKILL.md with frontmatter, directory structure, and optional resources.' +--- + +# Create Skill + +This skill helps you scaffold new agent skills that conform to the Agent Skills specification. Agent Skills are a lightweight, open format for extending AI agent capabilities with specialized knowledge and workflows. + +## When Not to Use + +- Creating custom agents (use the agents/ directory pattern) +- Adding language-specific, framework-specific, or module-specific coding guidelines (use file-based instructions instead) + +### Key Principles + +- **Frontmatter is critical**: `name` and `description` determine when the skill triggers—be clear and comprehensive +- **Concise is key**: Only include what agents don't already know; context window is shared +- **Useful instructions**: Only include information that's stable, not easily searchable and can be used for any task within the skill's scope +- **No duplication**: Information lives in SKILL.md OR reference files, not both + +## Workflow + +### Step 1: Investigate the Topic + +Build deep understanding of the relevant topics using the repository content, existing documentation, and any linked external resources. + +After investigating, verify: +- [ ] Can explain what the skill does in one paragraph +- [ ] Can list 3-5 specific scenarios where the skill is applicable +- [ ] Can identify common pitfalls or misconceptions about the topic +- [ ] Can outline a step-by-step skill workflow with clear validation steps +- [ ] Have search queries for deeper topics +- [ ] Can determine if the skill should be user-invokable or background knowledge only + +If there are any ambiguities, gaps in understanding, or multiple valid approaches, ask the user for clarification before proceeding to skill creation. +Also, evaluate whether the task might be better handled by a custom agent, agentic workflow, an existing skill or multiple narrower skills, and discuss this with the user if relevant. + +### Step 2: Create the skill directory + +``` +.agents/skills/<skill-name>/ +├── SKILL.md # Required: instructions + metadata +``` + +### Step 3: Generate SKILL.md with frontmatter + +Create the file with required YAML frontmatter: + +```yaml +--- +name: <skill-name> +description: <description of what the skill does and when to use it> +user-invokable: <Optional, defaults to true. Set to false for background knowledge skills.> +argument-hint: <Optional, guidance for how agents should format arguments when invoking the skill.> +disable-model-invocation: <Optional, set to true to prevent agents from invoking the skill and only allow to be used through manual invocation.> +compatibility: <Optional, specify any environment, tool, or context requirements for the skill.> +metadata: <Optional, key-value mapping for additional metadata that may be relevant for discovery or execution.> +allowed-tools: <Optional, list of pre-approved tools that agents could use when invoking the skill.> +--- +``` + +### Step 4: Add body content sections + +Include these recommended sections, following this file's structure: + +1. **<Human-readable skill name>**: One paragraph describing the outcome beyond what's already in the description +2. **When Not to Use**: Bullet list of exclusions, optional +3. **Inputs and Outputs**: Example inputs and expected outputs, if applicable +4. **Workflow**: Numbered steps with checkpoints +5. **Testing**: Instructions for how to create automated tests for the skill output, if applicable +6. **Validation**: How to confirm the skill worked correctly +7. **Common Pitfalls**: Known traps and how to avoid them, optional + +### Step 5: Add and populate optional directories if needed + +``` +.agents/skills/<skill-name>/ +├── SKILL.md +├── scripts/ # Optional: executable code that agents can run +├── references/ # Optional: REFERENCE.md (Detailed technical reference), FORMS.md (Form templates or structured data formats), domain-specific instruction files +└── assets/ # Optional: templates, resources and other data files that aren't executable or Markdown +``` + +### Step 6: Validate the skill + +Ensure the name: +- Does not start or end with a hyphen +- Does not contain consecutive hyphens +- Is between 1-64 characters +- YAML frontmatter name matches directory name exactly + +After creating a skill, verify: +- [ ] frontmatter fields are valid +- [ ] SKILL.md is under 500 lines and 5000 tokens, split into references if needed +- [ ] File references use relative paths +- [ ] Instructions are actionable and specific +- [ ] Instructions don't duplicate what's already in `.github/copilot-instructions.md` or under `.github/instructions/` +- [ ] Workflow has numbered steps with clear checkpoints +- [ ] Validation section exists with observable success criteria +- [ ] No secrets, tokens, or internal URLs included +- [ ] Common pitfalls are relevant and have solutions +- [ ] Optional directories are used appropriately +- [ ] Scripts handle edge cases gracefully and return structured outputs and helpful error messages when applicable + +## Common Pitfalls + +| Pitfall | Solution | +|---------|----------| +| Description is vague | Include what it does AND when to use it | +| Instructions are ambiguous | Use numbered steps with concrete actions | +| Missing validation steps | Add checkpoints that verify success | +| Hardcoded environment assumptions | Document requirements in `compatibility` field | +| Key files section lists files previously mentioned | Avoid duplication, only include in one place and rename section to "Other Key Files" | +| Testing section lists test folders that are obvious from the repo structure | Remove the section if it doesn't add value | + +## References + +- [Agent Skills Specification](https://agentskills.io/specification) +- [Copilot Instructions](../../../.github/copilot-instructions.md) +- [Contributing Guidelines](../../../.github/CONTRIBUTING.md) diff --git a/.agents/skills/migrations/SKILL.md b/.agents/skills/migrations/SKILL.md new file mode 100644 index 00000000000..a8e901937e2 --- /dev/null +++ b/.agents/skills/migrations/SKILL.md @@ -0,0 +1,17 @@ +--- +name: migrations +description: 'Implementation details for EF Core migrations. Use when changing MigrationsSqlGenerator, model diffing, migration operations, HistoryRepository, the Migrator or related classes.' +user-invokable: false +--- + +# Migrations + +## Pipeline + +**Add migration**: `MigrationsScaffolder.ScaffoldMigration()` → `MigrationsModelDiffer.GetDifferences()` → list of `MigrationOperation` → `CSharpMigrationsGenerator` and `CSharpSnapshotGenerator` produce Up/Down/Snapshot code + +**Apply migration**: `Migrator.MigrateAsync()` → reads `__EFMigrationsHistory` → per pending: `MigrationsSqlGenerator.Generate(operations)` → `MigrationCommandExecutor` executes + +## Testing + +Migration operation tests: `test/EFCore.Relational.Tests/Migrations/`. Functional tests: `test/EFCore.{Provider}.FunctionalTests/Migrations/`. Model differ tests: `test/EFCore.Relational.Tests/Migrations/Internal/MigrationsModelDifferTest*.cs`. \ No newline at end of file diff --git a/.agents/skills/model-building/SKILL.md b/.agents/skills/model-building/SKILL.md new file mode 100644 index 00000000000..1fbf29894b6 --- /dev/null +++ b/.agents/skills/model-building/SKILL.md @@ -0,0 +1,88 @@ +--- +name: model-building +description: 'Implementation details for EF Core model building. Use when changing ConventionSet, ModelBuilder, IConvention implementations, ModelRuntimeInitializer, RuntimeModel, or related classes.' +user-invokable: false +--- + +# Model Building, Conventions & Initialization + +Covers model construction (conventions, fluent API, metadata hierarchy) and model initialization (runtime annotation propagation, compiled model filtering). + +## Convention System + +`ConventionSet` (`src/EFCore/Metadata/Conventions/ConventionSet.cs`) holds `List<I*Convention>` for every metadata event. Key conventions in `src/EFCore/Metadata/Conventions/`: + +- `DbSetFindingConvention` — discovers entities from `DbSet<T>` +- `PropertyDiscoveryConvention` — discovers properties from CLR types +- `KeyDiscoveryConvention` — finds PKs (`Id`, `TypeId`) +- `RelationshipDiscoveryConvention` — infers FKs from navigations +- `RuntimeModelConvention` — creates optimized `RuntimeModel` from mutable model + +Override `ConfigureConventions(ModelConfigurationBuilder)` to add/remove conventions. + +## Metadata Interface Hierarchy + +`IReadOnly*` → `IMutable*` → `IConvention*` → `IRuntime*` + +Applies to: Model, EntityType, Property, Key, ForeignKey, Navigation, Index, etc. Builders follow: `*Builder` → `IConvention*Builder`. + +## Model Lifecycle + +1. **Mutable Model** — built by `ModelBuilder` during `OnModelCreating`, made read-only by `FinalizeModel()` +2. **Design-Time Model** — finalized read-only `Model` that also contains design-time-only annotations used in migrations +3. **Runtime Model** — an optimized read-only model created by `RuntimeModelConvention.ProcessModelFinalized()`, does not contain design-time-only annotations + +`ModelRuntimeInitializer.Initialize()` (called by `DbContextServices.CreateModel()`): + +``` +Initialize(model, designTime, validationLogger) +├─ FinalizeModel() if mutable +├─ Set ModelDependencies, InitializeModel +└─ RuntimeModelConvention creates RuntimeModel, copies/filters annotations +``` + +## Adding a New Annotation + +1. Add constant to `CoreAnnotationNames` and its `AllNames` +2. Filter in `RuntimeModelConvention.ProcessModelAnnotations` if it's a design-time-only annotation (only used in migration operations) +3. Filter in `CSharpRuntimeAnnotationCodeGenerator.Generate` if it can be computed lazily at runtime (e.g. based on other annotations) +4. Propagate in `RelationalAnnotationProvider` if used in up-migrations or the relational model and `IMigrationsAnnotationProvider` if used in down-migrations + +## Relational Model + +`RelationalModel` (`src/EFCore.Relational/Metadata/Internal/RelationalModel.cs`) is a database-centric view of the EF model, mapping entity types to physical database objects: `Tables`, `Views`, `Functions`, `Queries`, and `DefaultTables`. `DefaultTables` are pseudo-table objects only used for `FromSql` queries. + +Created lazily by `RelationalModelRuntimeInitializer`, accessed via `model.GetRelationalModel()`. Used by migrations (`MigrationsModelDiffer`), update and query pipelines. + +`RelationalAnnotationProvider` populates annotations on relational model elements. Provider subclasses (e.g., `SqlServerAnnotationProvider`) add provider-specific annotations. `IMigrationsAnnotationProvider` controls annotations used in down-migration operations. + +## Model Validation + +`ModelValidator` (`src/EFCore/Infrastructure/ModelValidator.cs`) and `RelationalModelValidator` (`src/EFCore.Relational/Infrastructure/RelationalModelValidator.cs`) run after model finalization, during `ModelRuntimeInitializer.Initialize()` between the pre- and post-validation `InitializeModel` calls. + +## Migration Snapshot Compatibility + +Model-building changes can trigger spurious migrations for users who upgrade. Two causes: + +1. **New metadata written to the snapshot** — old snapshots won't have it; `MigrationsModelDiffer` sees a diff. Fix: ensure absence of the annotation in an old snapshot is treated as the old default. +2. **Annotation renamed or reinterpreted** — old snapshots produce a different model. Fix: keep backward-compatible reading logic. + +Inspect `CSharpSnapshotGenerator` (what gets written) and `MigrationsModelDiffer` (how absence is handled). Add a snapshot round-trip test in `test/EFCore.Design.Tests/Migrations/ModelSnapshotSqlServerTest.cs`. + +## Testing + +| Area | Location | +|------|----------| +| Convention unit tests | `test/EFCore.Tests/Metadata/Conventions/` | +| Metadata unit tests | `test/EFCore.Tests/Metadata/Internal/` | +| Model builder API tests | `test/EFCore.Specification.Tests/ModelBuilding/ModelBuilderTest*.cs` | +| Relationship discovery tests | `test/EFCore.Specification.Tests/ModelBuilding101*.cs` | +| Model validation tests | `test/EFCore.Tests/Infrastructure/ModelValidatorTest*.cs` | + +## Validation + +- Model builds without `InvalidOperationException` during finalization +- All new API is covered by tests +- Compiled model baselines update cleanly with `EF_TEST_REWRITE_BASELINES=1` +- `ToString()` on metadata objects shows concise contents without throwing exceptions +- No spurious migration is generated against a project with an existing snapshot diff --git a/.agents/skills/query-pipeline/SKILL.md b/.agents/skills/query-pipeline/SKILL.md new file mode 100644 index 00000000000..246800506a3 --- /dev/null +++ b/.agents/skills/query-pipeline/SKILL.md @@ -0,0 +1,23 @@ +--- +name: query-pipeline +description: 'Implementation details for EF Core LINQ query translation and SQL generation. Use when changing expression visitors, SqlExpressions, QuerySqlGenerator, ShaperProcessingExpressionVisitor, or related classes.' +user-invokable: false +--- + +# Query Pipeline + +Translates LINQ expressions into database queries and materializes results. + +## Stages + +1. **Preprocessing** — `QueryTranslationPreprocessor`: `NavigationExpandingExpressionVisitor` (Include, navigations, auto-includes), `QueryOptimizingExpressionVisitor` +2. **Translation** — `QueryableMethodTranslatingExpressionVisitor`: LINQ methods → `ShapedQueryExpression` (= `QueryExpression` + `ShaperExpression`). Relational: `RelationalSqlTranslatingExpressionVisitor`, `SelectExpression` +3. **Postprocessing** — `QueryTranslationPostprocessor`: `SqlNullabilityProcessor`, `SqlTreePruner`, `SqlAliasManager`, `RelationalParameterBasedSqlProcessor`, `RelationalSqlProcessingExpressionVisitor` +4. **Compilation** — `ShapedQueryCompilingExpressionVisitor` → executable delegate. Relational: `ShaperProcessingExpressionVisitor` builds shaper and materialization code +5. **SQL Generation** — `QuerySqlGenerator` + +## Validation + +- `ToQueryString()` shows generated SQL without executing +- `ExpressionPrinter` dumps expression trees at any pipeline stage +- SQL baselines verified via `AssertSql()` in provider functional tests diff --git a/.agents/skills/scaffolding/SKILL.md b/.agents/skills/scaffolding/SKILL.md new file mode 100644 index 00000000000..54b3bf72da6 --- /dev/null +++ b/.agents/skills/scaffolding/SKILL.md @@ -0,0 +1,18 @@ +--- +name: scaffolding +description: 'Implementation details for EF Core scaffolding (reverse engineering). Use when changing ef dbcontext scaffold pipeline implementation, database schema reading, CSharpModelGenerator, or related classes.' +user-invokable: false +--- + +# Scaffolding + +Generates C# code from database schemas (reverse engineering). + +## When Not to Use + +- Working on compiled model generation (`dotnet ef dbcontext optimize`) + +## Reverse Engineering + +Pipeline: `IDatabaseModelFactory` (reads schema) → `IScaffoldingModelFactory` (builds EF model) → `IModelCodeGenerator` (generates C#) +- `IReverseEngineerScaffolder` — orchestrates full pipeline diff --git a/.agents/skills/servicing-pr/SKILL.md b/.agents/skills/servicing-pr/SKILL.md new file mode 100644 index 00000000000..958d631ef92 --- /dev/null +++ b/.agents/skills/servicing-pr/SKILL.md @@ -0,0 +1,65 @@ +--- +name: servicing-pr +description: 'Create EF Core PRs targeting servicing release branches (release/*). Use when working on a PR that targets a release branch, backporting a fix from main, or when the user mentions servicing, patch, or release branch.' +--- + +# Servicing PRs + +PRs targeting `release/*` branches require a specific description format and should include a quirk (AppContext switch) when applicable. + +## Backport Target Branch + +- If a version is specified, target `release/XX.0` (e.g., `backport to 10` → `release/10.0`) +- Otherwise, find the latest `release/XX.0` branch (ignore preview branches like `release/11.0-preview2`) +- Verify the branch exists before creating the PR + +## PR Title + +`[release/XX.0] <original PR title>` + +## PR Description Template + +``` +Fixes #{issue_number} +Backports #{source_pr_number_if_applicable} + +**Description** +Provide information on the bug, why it occurs and how it was introduced. Put it in terms that developers can understand without knowledge of EF Core internals. + +**Customer impact** +How the bug affects users without internal technical detail. Include a short (3-4 lines) code sample if possible. If data corruption occurs, state that explicitly. If a feasible workaround exists, briefly describe it and how discoverable it is, otherwise mention that there's no workaround. + +**How found** +How the bug was discovered based on the information in the issue description. If user-reported, mention "User reported on <version>". If multiple users are affected, note that. Count the number of upvotes and comment authors to estimate impact. + +**Regression** +Whether this is a regression from an earlier EF version. Add a link to the PR that introduced the regression if known. If it only affects a feature introduced in the same major version, it is not a regression. + +**Testing** +State the number of new or modified tests, don't go into details. If test coverage is unfeasible, briefly explain the alternative validation approach that was used. + +**Risk** +Brief risk assessment ranked from "extremely low" to "high". Note amount of code changed. If the fix is a one-liner, mention that. If a quirk was added, mention "Quirk added". +``` + +## Quirk (AppContext Switch) + +A quirk lets users opt out of the fix at runtime, reducing patch risk. Add for all cases where it makes sense. Skip when the fix is 100% obvious/risk-free, or when the quirk couldn't be used, like in tools or analyzers. + +### Adding a Quirk + +Add in the class(es) containing code changes: + +```csharp +private static readonly bool UseOldBehavior37585 = + AppContext.TryGetSwitch("Microsoft.EntityFrameworkCore.Issue37585", out var enabled) && enabled; +``` + +- Change `37585` to the relevant issue number +- Wrap changes with a condition on `!UseOldBehavior37585` so activating the switch bypasses the fix, prefer to minimize the number of times the switch is checked +- If the PR closes multiple issues, pick the most appropriate one for the switch name + +## Validation + +- PR description follows the template completely (all sections filled) +- Quirk added where appropriate with issue number matching the PR description diff --git a/.agents/skills/sqlite-adonet/SKILL.md b/.agents/skills/sqlite-adonet/SKILL.md new file mode 100644 index 00000000000..17a5e9c267a --- /dev/null +++ b/.agents/skills/sqlite-adonet/SKILL.md @@ -0,0 +1,14 @@ +--- +name: sqlite-adonet +description: 'Implementation details for the Microsoft.Data.Sqlite ADO.NET provider. Use when changing files under `src/Microsoft.Data.Sqlite.Core/`.' +user-invokable: false +--- + +# Microsoft.Data.Sqlite + +Standalone ADO.NET provider in `src/Microsoft.Data.Sqlite.Core/`, independent of EF Core. Implements `System.Data.Common` abstractions. + +## Notable Implementation Details + +- Static constructor calls `SQLitePCL.Batteries_V2.Init()` reflectively +- `CreateFunction()`/`CreateAggregate()` overloads generated from T4 templates (`.tt` files) diff --git a/.agents/skills/testing/SKILL.md b/.agents/skills/testing/SKILL.md new file mode 100644 index 00000000000..99fdc86f556 --- /dev/null +++ b/.agents/skills/testing/SKILL.md @@ -0,0 +1,79 @@ +--- +name: testing +description: 'Implementation details for EF Core test infrastructure. Use when changing test fixtures, SQL baseline assertions, test helpers, the test class hierarchy, or when adding new tests.' +user-invokable: false +--- + +# Testing + +EF Core test infrastructure, patterns, and workflows for unit, specification, and functional tests. + +## Test Categories + +### Unit Tests (`test/EFCore.{Provider}.Tests/`) +Isolated logic tests. Build models via `*TestHelpers.Instance.CreateConventionBuilder()`, resolve services from `CreateContextServices()`. No database needed. + +### Specification Tests (provider-agnostic abstract bases) +Define WHAT to test (LINQ queries, expected results). Can't be run directly — provider tests override to verify HOW (generated SQL). + +- Core → `test/EFCore.Specification.Tests/` +- Relational → `test/EFCore.Relational.Specification.Tests/` + +### Functional Tests (`test/EFCore.{Provider}.FunctionalTests/`) +Concrete provider tests inheriting specification tests. Most include SQL baseline assertions. + +## Test Class Hierarchy (Query Example) + +``` +QueryTestBase<TFixture> # Core + └─ NorthwindWhereQueryTestBase<TFixture> # Specification + └─ NorthwindWhereQueryRelationalTestBase<TFixture> # Relational specification + └─ NorthwindWhereQuerySqlServerTest # Provider (asserts SQL) +``` + +Provider override pattern: +```csharp +public override async Task Where_simple(bool async) +{ + await base.Where_simple(async); // runs LINQ + asserts results + AssertSql("""..."""); // asserts provider-specific SQL +} +``` + +## TestHelpers Hierarchy + +``` +TestHelpers (abstract) # EFCore.Specification.Tests + ├─ InMemoryTestHelpers # non-relational + └─ RelationalTestHelpers (abstract) # EFCore.Relational.Specification.Tests + ├─ SqlServerTestHelpers + └─ SqliteTestHelpers +``` + +Key methods: `CreateConventionBuilder()`, `CreateContextServices(model)`, `CreateOptions()` + +## Fixtures + +### SharedStoreFixtureBase<TContext> +Many tests share one database. Creates `TestStore` + pooled `DbContextFactory` in `InitializeAsync()`. Seeds data once. Use for read-heavy tests (e.g., Northwind query tests). + +### NonSharedModelTestBase +Each test gets a fresh model/store. Call `InitializeAsync<TContext>(onModelCreating, seed, ...)` per test. Use for tests needing unique schemas. + +## SQL Baseline Assertions + +`TestSqlLoggerFactory` captures SQL. `AssertSql("""...""")` compares against expected. Set `EF_TEST_REWRITE_BASELINES=1` to auto-rewrite baselines via Roslyn. + +## Workflow: Adding New Tests + +1. **Specification test**: Add to `EFCore.Specification.Tests` (core) or `EFCore.Relational.Specification.Tests` (relational) +2. **Provider override**: Override in `EFCore.{Provider}.FunctionalTests` with `AssertSql()` +3. **Unit test**: Add to `EFCore.{Provider}.Tests` +4. Run with `EF_TEST_REWRITE_BASELINES=1` to capture initial baselines + +## Common Pitfalls + +| Pitfall | Solution | +|---------|----------| +| SQL or Compiled model baseline mismatch | Set `EF_TEST_REWRITE_BASELINES=1` and re-run | +| `Check_all_tests_overridden` fails | Override new base test in provider test class | diff --git a/.agents/skills/tooling/SKILL.md b/.agents/skills/tooling/SKILL.md new file mode 100644 index 00000000000..b6d6217d858 --- /dev/null +++ b/.agents/skills/tooling/SKILL.md @@ -0,0 +1,39 @@ +--- +name: tooling +description: 'Implementation details for the EF Core dotnet-ef CLI and tooling. Use when changing dotnet-ef commands, the ef wrapper, EFCore.Tools (PMC), or EFCore.Tasks MSBuild integration.' +user-invokable: false +--- + +# Tooling + +The `dotnet ef` CLI and Visual Studio Package Manager Console commands for migrations, scaffolding, and compiled models. + +## dotnet-ef CLI (`src/dotnet-ef/`) + +`RootCommand` parses global options (`--project`, `--startup-project`, `--framework`, `--configuration`, `--runtime`, `--no-build`). Subcommands in `Commands/`: `DatabaseCommand`, `DbContextCommand`, `MigrationsCommand`. Each invokes MSBuild to build, then shells out via `dotnet exec ef.dll`, which hosts `OperationExecutor`. + +## PMC (`src/EFCore.Tools/`) + +PowerShell module: `Add-Migration`, `Update-Database`, `Scaffold-DbContext`, `Optimize-DbContext`, etc. Routes to `OperationExecutor`. + +## MSBuild Tasks (`src/EFCore.Tasks/`) + +NuGet package `Microsoft.EntityFrameworkCore.Tasks` provides build/publish-time compiled model and precompiled query generation. + +### Build Integration Flow + +Targets in `buildTransitive/Microsoft.EntityFrameworkCore.Tasks.targets`: +- **Build flow**: `_EFGenerateFilesAfterBuild` triggers after compilation when `EFOptimizeContext=true` and stage is `build`. Invokes `OptimizeDbContext` task, writes generated file list, re-triggers `Build` to compile new files. +- **Publish flow**: `_EFGenerateFilesBeforePublish` runs before `GeneratePublishDependencyFile`. Auto-activates for `PublishAOT=true`. `_EFPrepareDependenciesForPublishAOT` cascades to project references. +- **Incremental**: `_EFProcessGeneratedFiles` reads tracking files and adds `.g.cs` to `@(Compile)`. Stale files removed by `_EFPrepareForCompile`. +- **Clean**: `_EFCleanGeneratedFiles` deletes generated and tracking files. + +## Testing + +- CLI tests: `test/dotnet-ef.Tests/`, `test/ef.Tests/` +- EFCore.Tasks has no dedicated test project — for task/target changes, create a test project and manually run `dotnet build` / `dotnet publish` with `EFOptimizeContext=true` to verify + +## Validation + +- For tool changes, create a test project and manually run affected commands to verify behavior +- `dotnet ef migrations script` output matches expected DDL \ No newline at end of file diff --git a/.agents/skills/update-pipeline/SKILL.md b/.agents/skills/update-pipeline/SKILL.md new file mode 100644 index 00000000000..50ee6009776 --- /dev/null +++ b/.agents/skills/update-pipeline/SKILL.md @@ -0,0 +1,34 @@ +--- +name: update-pipeline +description: 'Implementation details for EF Core SaveChanges and the update pipeline. Use when changing CommandBatchPreparer, UpdateSqlGenerator, ModificationCommand, or related classes.' +user-invokable: false +--- + +# Update Pipeline + +Converts tracked entity changes into database INSERT/UPDATE/DELETE commands during `SaveChanges()`. + +## Flow + +`SaveChanges()` → `DetectChanges()` → `IDatabase.SaveChanges()` + → `UpdateAdapter` creates `IUpdateEntry` list + → `CommandBatchPreparer.BatchCommands()` + → `ModificationCommand` per entity (maps to table row), composed of `ColumnModification` (maps to column value) + → Topological sort via Multigraph (FK dependency ordering) + → Groups into `ModificationCommandBatch` (respects max batch size) + → `UpdateSqlGenerator` generates SQL per batch + → `BatchExecutor` executes all batches in a transaction + → `StateManager.AcceptAllChanges()` + +Other Key Files: +- `src/EFCore.Relational/Update/Internal/SharedTableEntryMap.cs` — manages entries mapped to the same row + +## Concurrency + +Concurrency tokens → WHERE conditions on UPDATE/DELETE. `AffectedCountModificationCommandBatch` checks affected rows. Throws `DbUpdateConcurrencyException` on mismatch. + +## Validation + +- `SaveChanges()` returns expected affected row count +- Store-generated values propagate back to entities after INSERT/UPDATE +- `DbUpdateConcurrencyException` thrown when expected for stale data diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 31040f8d499..0b8b2547e3f 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -148,11 +148,10 @@ If you are not sure, do not guess, just tell that you don't know or ask clarifyi - Prefer using `Check.DebugAssert` instead of `Debug.Assert` or comments - Use `Check.NotNull` and `Check.NotEmpty` for preconditions in public APIs - The methods in `Check` class use `[CallerArgumentExpression]` to automatically capture parameter names -- Unit tests should build the model using the corresponding `*TestHelpers.Instance.CreateConventionBuilder()` model and finalizing it -- The services in unit tests should be resolved from the `IServiceProvider` returned by `*TestHelpers.Instance.CreateContextServices`, note that it has overloads allowing to specify the model and mock services -- For functional tests, create tests in projects corresponding to the database providers that derive from the appropriate test base classes in the `EFCore.*Specification.Tests` projects -- Each provider has its own project structure: `EFCore.{Provider}`, `EFCore.{Provider}.Tests`, `EFCore.{Provider}.FunctionalTests` -- Specification tests (`EFCore.*.Specification.Tests`) define provider-agnostic functional tests + +## Agent Skills + +Skill files in `.agents/skills/` provide domain-specific knowledge for Copilot agents. When you spend significant time investigating the codebase to understand an implementation during a session (e.g., tracing through code paths, discovering key files, understanding non-obvious patterns), update the relevant skill's `SKILL.md` with your findings so future tasks can be completed more efficiently. Only add information that is broadly useful and not specific to a single task. Keep additions concise and stable, avoid speculation or information that can be easily found by reading a single file. ## Repository Structure @@ -168,87 +167,8 @@ If you are not sure, do not guess, just tell that you don't know or ask clarifyi ## Pull Request Guidelines - **ALWAYS** target the `main` branch for new PRs unless explicitly instructed otherwise +- For servicing PRs (fixes targeting release branches), use the `servicing-pr` skill ## Overview of Entity Framework Core -Entity Framework Core (EF Core) is an object-database mapper for .NET. Below is a concise summary of its core architecture and concepts: - -### DbContext & Pooling -- `DbContext` is the main API for interacting with EF Core. It manages entity objects, queries, and changes. -- Configuration is done via `OnConfiguring` or dependency injection (DI) in modern apps. -- Pooling (`AddDbContextPool`) reuses context instances for performance in high-throughput scenarios. -- Contexts are short-lived; pooling resets state but does not dispose underlying services. - -### Query Pipeline -- LINQ queries build expression trees, which EF Core translates into database queries (e.g., SQL). -- The pipeline includes translation, optimization, provider-specific SQL generation, and execution. -- Compiled queries are cached for performance. -- Deferred execution: queries run when enumerated (e.g., `ToList()`). - -### Materialization (Shaper) -- Converts raw database results into .NET entity objects. -- Handles property assignment, relationship fix-up, and tracking (if enabled). -- Uses compiled functions for efficient repeated materialization. - -### Change Tracking -- Tracks entity states: Added, Modified, Deleted, Unchanged, Detached. -- Detects changes via snapshots or proxies. -- Drives the update pipeline for `SaveChanges()`. -- Non-tracking queries (`AsNoTracking`) improve read performance. - -### SaveChanges & Update Pipeline -- Gathers tracked changes and generates database commands (INSERT, UPDATE, DELETE). -- Orders operations to maintain referential integrity. -- Executes in a transaction by default; supports batching. -- Handles concurrency via tokens and exceptions. - -### Bulk Operations -- `ExecuteUpdate`/`ExecuteDelete` perform set-based updates/deletes directly in the database, bypassing change tracking. -- Bulk inserts are batched, but not true multi-row SQL by default. - -### Model Building & Conventions -- The model defines entities, properties, keys, relationships, and mappings. -- Built via conventions, data annotations, and the fluent API (`OnModelCreating`). -- Pre-convention configuration allows specifying model-wide rules and change used conventions. -- API follows the pattern: `*Builder` → `IConvention*Builder`, `IReadOnly*` → `IMutable*` → `IConvention*` → `IRuntime*` -- The interfaces are implemented by mutable and runtime models that provide the same behavior, but different perf characteristics -- Model is cached for performance. -- Compiled model is generated by `CSharpRuntimeModelCodeGenerator`, `*CSharpRuntimeAnnotationCodeGenerator` and `CSharpDbContextGenerator` -- Relational providers also use `RelationalModel` and `*AnnotationProvider` - -### Model Components -- Entity Types: .NET classes mapped to tables/collections. -- Properties: Scalar, navigation, shadow, or service properties. -- Keys: Primary and alternate keys for identity and relationships. -- Foreign Keys/Relationships: Define associations between entities. -- Navigation Properties: Reference or collection navigations. -- Owned Types: Entity types that are part of an aggregate, no independent identity. -- Complex Types: Value objects embedded in entities, no independent identity. -- Primitive Collections: Collections of scalars, often mapped to JSON columns. - -### Storage & Type Mapping -- Maps .NET types to database types, with support for value converters. -- Provider-specific logic handles differences (e.g., SQL Server vs. SQLite). -- Ensures data round-trips correctly between CLR and database. - -### Scaffolding (Reverse Engineering) -- Generates model and context code from an existing database schema. -- Useful for starting code-first development from a legacy database. - -### Database Providers -- EF Core is database-agnostic; providers implement translation, type mapping, and database-specific behaviors. -- Choose the correct provider (e.g., SQL Server, SQLite, PostgreSQL) via NuGet and configuration. - -### Migrations -- Incrementally evolve the database schema to match model changes. -- Add, update, or remove migrations; apply them via CLI or code. -- Maintains a migration history table in the database. - -### Command-Line Tools -- `dotnet ef` and Package Manager Console (PMC) provide commands for migrations, scaffolding, and model optimization. -- Tools integrate with MSBuild and require the design package. - -### Compiled Models -- A generated static representation of the model for faster startup in large projects. -- Must be regenerated if the model changes. -- Required for NativeAOT scenarios. +Entity Framework Core (EF Core) is an object-database mapper for .NET. It manages entity objects via `DbContext`, translates LINQ queries into database queries, tracks entity changes, and persists them via `SaveChanges()`. The model defines entities, properties, keys, relationships, and mappings — built via conventions, data annotations, and the fluent API. EF Core is database-agnostic; providers implement translation, type mapping, and database-specific behaviors. See the skills in `.agents/skills/` for detailed architecture of each subsystem.