From 485da14ce4cf95bf76815cdf3502c904d1889c5d Mon Sep 17 00:00:00 2001 From: Andriy Svyryd Date: Sat, 21 Feb 2026 19:00:42 -0800 Subject: [PATCH 01/14] Add background information skills --- .agents/skills/analyzers/SKILL.md | 34 +++++ .agents/skills/bulk-operations/SKILL.md | 46 +++++++ .agents/skills/change-tracking/SKILL.md | 66 ++++++++++ .agents/skills/cosmos-provider/SKILL.md | 43 ++++++ .../skills/dbcontext-and-services/SKILL.md | 49 +++++++ .agents/skills/make-skill/SKILL.md | 123 ++++++++++++++++++ .agents/skills/migrations/SKILL.md | 37 ++++++ .agents/skills/model-building/SKILL.md | 91 +++++++++++++ .agents/skills/query-pipeline/SKILL.md | 62 +++++++++ .agents/skills/scaffolding/SKILL.md | 42 ++++++ .agents/skills/servicing-pr/SKILL.md | 70 ++++++++++ .agents/skills/sqlite-adonet/SKILL.md | 40 ++++++ .agents/skills/testing/SKILL.md | 85 ++++++++++++ .agents/skills/tooling/SKILL.md | 59 +++++++++ .agents/skills/update-pipeline/SKILL.md | 55 ++++++++ .github/copilot-instructions.md | 92 +------------ 16 files changed, 908 insertions(+), 86 deletions(-) create mode 100644 .agents/skills/analyzers/SKILL.md create mode 100644 .agents/skills/bulk-operations/SKILL.md create mode 100644 .agents/skills/change-tracking/SKILL.md create mode 100644 .agents/skills/cosmos-provider/SKILL.md create mode 100644 .agents/skills/dbcontext-and-services/SKILL.md create mode 100644 .agents/skills/make-skill/SKILL.md create mode 100644 .agents/skills/migrations/SKILL.md create mode 100644 .agents/skills/model-building/SKILL.md create mode 100644 .agents/skills/query-pipeline/SKILL.md create mode 100644 .agents/skills/scaffolding/SKILL.md create mode 100644 .agents/skills/servicing-pr/SKILL.md create mode 100644 .agents/skills/sqlite-adonet/SKILL.md create mode 100644 .agents/skills/testing/SKILL.md create mode 100644 .agents/skills/tooling/SKILL.md create mode 100644 .agents/skills/update-pipeline/SKILL.md diff --git a/.agents/skills/analyzers/SKILL.md b/.agents/skills/analyzers/SKILL.md new file mode 100644 index 00000000000..465199020ef --- /dev/null +++ b/.agents/skills/analyzers/SKILL.md @@ -0,0 +1,34 @@ +--- +name: analyzers +description: 'EF Core Roslyn analyzers, diagnostic analyzers, code fix providers, diagnostic suppressors. Use when working on EF1001, EF1002, InternalUsageDiagnosticAnalyzer, or StringsUsageInRawQueriesDiagnosticAnalyzer.' +user-invokable: false +--- + +# EF Core Analyzers + +Roslyn analyzers shipped in `Microsoft.EntityFrameworkCore.Analyzers` (`src/EFCore.Analyzers/`). + +## When to Use + +- Adding a new diagnostic rule or code fix +- Modifying detection logic for internal API usage or SQL injection warnings +- Working on a diagnostic suppressor + +## Analyzers + +| ID | Analyzer | Category | Purpose | +|----|----------|----------|---------| +| EF1001 | `InternalUsageDiagnosticAnalyzer` (333 lines) | Usage | Warns on `.Internal` namespace / `[EntityFrameworkInternal]` usage. Registers operation + symbol actions for field, property, method, event, invocation, object creation, variable declaration, typeof, named type. | +| EF1002 | `StringsUsageInRawQueriesDiagnosticAnalyzer` (254 lines) | Security | Two diagnostics: interpolated string usage and string concatenation in raw SQL methods. Registers `OperationKind.Invocation` action. | +| — | `InterpolatedStringUsageInRawQueriesCodeFixProvider` | — | Fix for EF1002: `FromSqlRaw` → `FromSqlInterpolated` | +| — | `UninitializedDbSetDiagnosticSuppressor` | — | Suppresses CS8618 for `DbSet` properties on `DbContext` | + +## Testing + +Tests in `test/EFCore.Analyzers.Tests/` use `CSharpAnalyzerVerifier`. Test methods provide inline C# source with diagnostic location markers. Pattern: + +## Validation + +- Analyzer triggers on expected code patterns +- No false positives on public API usage +- Code fix produces compilable output diff --git a/.agents/skills/bulk-operations/SKILL.md b/.agents/skills/bulk-operations/SKILL.md new file mode 100644 index 00000000000..1767d300778 --- /dev/null +++ b/.agents/skills/bulk-operations/SKILL.md @@ -0,0 +1,46 @@ +--- +name: bulk-operations +description: 'EF Core ExecuteUpdate, ExecuteDelete, set-based bulk CUD operations. Use when working on bulk update/delete LINQ translation or UpdateExpression/DeleteExpression SQL AST nodes.' +user-invokable: false +--- + +# Bulk Operations + +`ExecuteUpdate`/`ExecuteDelete` translate LINQ to set-based SQL UPDATE/DELETE, bypassing change tracking. Return affected row count. + +## When to Use + +- Adding or fixing translation of `ExecuteUpdate`/`ExecuteDelete` +- Working on `UpdateExpression`/`DeleteExpression` SQL AST nodes +- Handling provider-specific UPDATE/DELETE syntax differences + +## Key Files + +- Translation: `RelationalQueryableMethodTranslatingExpressionVisitor.ExecuteUpdate.cs` / `.ExecuteDelete.cs` +- SQL AST: `UpdateExpression.cs`, `DeleteExpression.cs` in `src/EFCore.Relational/Query/SqlExpressions/` +- Public API: `EntityFrameworkQueryableExtensions` — `ExecuteDelete`, `ExecuteUpdate` + async +- Setters: `SetPropertyCalls.cs`, `UpdateSettersBuilder.cs` + +## Unsupported Scenarios + +These throw at translation time — know them before attempting changes: + +| Scenario | Error | +|----------|-------| +| TPC (non-leaf types) | `ExecuteOperationOnTPC` | +| TPT (ExecuteDelete) | `ExecuteOperationOnTPT` | +| JSON-mapped owned entities | `ExecuteOperationOnOwnedJsonIsNotSupported` | +| JSON-mapped complex types | `ExecuteUpdateOverJsonIsNotSupported` | +| Complex types in subqueries | `ExecuteUpdateSubqueryNotSupportedOverComplexTypes` | +| Keyless entities | `ExecuteOperationOnKeylessEntityTypeWithUnsupportedOperator` | +| Entity splitting (Delete) | `ExecuteOperationOnEntitySplitting` | +| Table splitting (Delete) | `ExecuteDeleteOnTableSplitting` | + +## Testing + +Specification tests: `test/EFCore.Specification.Tests/BulkUpdates/NorthwindBulkUpdatesTestBase.cs`. Uses `AssertDelete(async, query, rowsAffectedCount)` / `AssertUpdate(...)`. Provider overrides in `test/EFCore.{Provider}.FunctionalTests/BulkUpdates/` with `AssertSql()` baselines. + +## Validation + +- New operations translate to correct SQL +- Unsupported scenarios throw at translation time, not at runtime diff --git a/.agents/skills/change-tracking/SKILL.md b/.agents/skills/change-tracking/SKILL.md new file mode 100644 index 00000000000..5964010fe9b --- /dev/null +++ b/.agents/skills/change-tracking/SKILL.md @@ -0,0 +1,66 @@ +--- +name: change-tracking +description: 'EF Core change tracking, entity states, StateManager, snapshot comparison, change detection, complex properties/collections, property values, property accessors, proxies. Use when working on InternalEntityEntry, ChangeDetector, or SnapshotFactoryFactory.' +user-invokable: false +--- + +# Change Tracking + +Manages entity states and detects changes for `SaveChanges()`. + +## When to Use + +- Modifying how entity state transitions work +- Working on snapshot comparison or change detection +- Debugging property accessor expression trees or ordinal indexing +- Working on change tracking or lazy loading proxies + +## Core Components + +- `StateManager` — central engine, identity maps, tracks all entities +- `InternalEntityEntry` — per-entity state, property flags, snapshots +- `ChangeDetector` — calls `DetectChanges()` which compares snapshots +- `ChangeTracker` — public API wrapping StateManager + +## Snapshots + +Built by `SnapshotFactoryFactory` subclasses via compiled expression trees: +- `OriginalValuesFactoryFactory` — for detecting property changes +- `RelationshipSnapshotFactoryFactory` — for FK/navigation fix-up + +## Property Accessors + +Compiled expression trees in `PropertyAccessorsFactory`: +- `CreateMemberAccess()` — entity → complex property → nested property +- `CreateComplexCollectionElementAccess()` — entity → collection → element[ordinal] → property +- Ordinals in `indices` parameter specify element at each collection depth +- Guard expressions added when `DetailedErrorsEnabled` annotation is set on the model + +Getters compiled lazily via `ClrPropertyGetterFactory` → `ClrPropertyGetter`. Two delegates: +- `GetClrValue(instance)` — from immediate declaring object +- `GetClrValueUsingContainingEntity(entity, indices)` — from root entity through complex chain + +## Key Files + +- `src/EFCore/ChangeTracking/Internal/StateManager.cs` +- `src/EFCore/ChangeTracking/Internal/InternalEntityEntry.cs` +- `src/EFCore/ChangeTracking/Internal/ChangeDetector.cs` +- `src/EFCore/Metadata/Internal/PropertyAccessorsFactory.cs` +- `src/EFCore/Metadata/Internal/ClrPropertyGetterFactory.cs` +- `src/EFCore/ChangeTracking/Internal/SnapshotFactoryFactory.cs` + +## Testing + +Unit tests: `test/EFCore.Tests/ChangeTracking/`. Functional tests: `test/EFCore.{Provider}.FunctionalTests/`. + +## Common Pitfalls + +| Pitfall | Solution | +|---------|----------| +| `SharedIdentityEntry` for deleted entities (table splitting) | These are skipped by `DetectChanges` to avoid double-processing | + +## Validation + +- Entity states transition correctly (`Added` → `Unchanged` after save, etc.) +- `DetectChanges()` identifies modified properties via snapshot comparison +- Property accessor expression trees compile without errors at runtime diff --git a/.agents/skills/cosmos-provider/SKILL.md b/.agents/skills/cosmos-provider/SKILL.md new file mode 100644 index 00000000000..15016f0d730 --- /dev/null +++ b/.agents/skills/cosmos-provider/SKILL.md @@ -0,0 +1,43 @@ +--- +name: cosmos-provider +description: 'EF Core Azure Cosmos DB provider, Cosmos query translation, Cosmos SQL generation, document storage, partition keys. Use when working on CosmosQueryableMethodTranslatingExpressionVisitor, CosmosClientWrapper, or Cosmos-specific features.' +user-invokable: false +--- + +# Cosmos DB Provider + +Non-relational provider with its own parallel query pipeline. Uses JSON for document materialization. + +## When to Use + +- Adding or modifying Cosmos query translation +- Working on document storage, partition key configuration, or `CosmosClientWrapper` +- Debugging Cosmos SQL generation differences from relational SQL + +## Key Differences from Relational + +- No migrations — use `EnsureCreated()` +- Documents as JSON — owned types become embedded objects +- Partition key configuration required for performance +- Limited query translation (more client evaluation) +- `ETag` for optimistic concurrency +- No cross-container joins + +## Key Files + +| Area | Path | +|------|------| +| LINQ → Cosmos | `src/EFCore.Cosmos/Query/Internal/CosmosQueryableMethodTranslatingExpressionVisitor.cs` | +| Expression → Cosmos SQL | `src/EFCore.Cosmos/Query/Internal/CosmosSqlTranslatingExpressionVisitor.cs` | +| SQL generation | `src/EFCore.Cosmos/Query/Internal/CosmosQuerySqlGenerator.cs` | +| Compilation | `src/EFCore.Cosmos/Query/Internal/CosmosShapedQueryCompilingExpressionVisitor.cs` | +| Cosmos SDK wrapper | `src/EFCore.Cosmos/Storage/Internal/CosmosClientWrapper.cs` | +| SQL AST nodes | `src/EFCore.Cosmos/Query/Internal/Expressions/` (~33 expression types) | + +## Testing + +Unit tests: `test/EFCore.Cosmos.Tests/`. Functional tests: `test/EFCore.Cosmos.FunctionalTests/`. + +## Validation + +- Provider functional tests pass against a Cosmos emulator or live instance diff --git a/.agents/skills/dbcontext-and-services/SKILL.md b/.agents/skills/dbcontext-and-services/SKILL.md new file mode 100644 index 00000000000..288d9ff8c5c --- /dev/null +++ b/.agents/skills/dbcontext-and-services/SKILL.md @@ -0,0 +1,49 @@ +--- +name: dbcontext-and-services +description: 'EF Core DbContext, DbContextOptions, dependency injection, service registration, DbContext pooling, IServiceProvider management. Use when working on context configuration, service lifetimes, or the Dependencies pattern.' +user-invokable: false +--- + +# DbContext & Services + +EF Core's internal DI container, service registration, and context lifecycle management. + +## When to Use + +- Adding a new EF Core service or changing service lifetimes +- Working on DbContext pooling behavior +- Modifying how options extensions are processed +- Understanding the `Dependencies` record pattern for service injection + +## Service Registration + +`EntityFrameworkServicesBuilder` (`src/EFCore/Infrastructure/EntityFrameworkServicesBuilder.cs`, 531 lines) maintains a `CoreServices` dictionary mapping service types to `ServiceCharacteristics` (lifetime + multi-registration flag). `TryAddCoreServices()` registers ~60+ services. + +Pattern: Providers call `TryAddProviderSpecificServices()` first, then `TryAddCoreServices()` fills remaining defaults. + +## Dependencies Pattern + +Services receive dependencies via sealed records (not constructor injection of individual services): +```csharp +public sealed record MyServiceDependencies(IDep1 Dep1, IDep2 Dep2); +``` + +## DbContext Pooling + +`DbContextPool` uses `ConcurrentQueue`. Default pool size: 1024. Set via `CoreOptionsExtension.MaxPoolSize`. Options are frozen at pool creation. + +## Key Files + +- `src/EFCore/DbContext.cs` — main context, implements `IDbContextPoolable` +- `src/EFCore/Infrastructure/DbContextOptions.cs` — immutable sorted dictionary of `IDbContextOptionsExtension` +- `src/EFCore/Infrastructure/EntityFrameworkServicesBuilder.cs` — service registration +- `src/EFCore/Internal/DbContextServices.cs` — scoped service resolver, model creation, provider validation +- `src/EFCore/Internal/DbContextPool.cs` — pooling implementation + +## Testing + +Unit tests: `test/EFCore.Tests/` (e.g., `DbContextTest.cs`, `EntityFrameworkServiceCollectionExtensionsTest.cs`). + +## Validation + +- Service resolution uses appropriate lifetimes and doesn't throw diff --git a/.agents/skills/make-skill/SKILL.md b/.agents/skills/make-skill/SKILL.md new file mode 100644 index 00000000000..809df28c60f --- /dev/null +++ b/.agents/skills/make-skill/SKILL.md @@ -0,0 +1,123 @@ +--- +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 to Use + +- Creating a new skill from scratch +- Generating a SKILL.md file with proper frontmatter in compliance with agentskills.io specification + +## When Not to Use + +- Creating custom agents (use the agents/ directory pattern) + +### 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. + +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 would 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.md # Required: instructions + metadata +``` + +### Step 3: Generate SKILL.md with frontmatter + +Create the file with required YAML frontmatter: + +```yaml +--- +name: +description: +user-invokable: +argument-hint: +disable-model-invocation: +compatibility: +metadata: +allowed-tools: +--- +``` + +### Step 4: Add body content sections + +Include these recommended sections, following this file's structure: + +1. ****: One paragraph describing the outcome beyond what's already in the description +2. **When to Use**: Bullet list of appropriate scenarios +3. **When Not to Use**: Bullet list of exclusions, optional +4. **Inputs and Outputs**: Example inputs and expected outputs, if applicable +5. **Workflow**: Numbered steps with checkpoints +6. **Testing**: Instructions for how to create automated tests for the skill output, if applicable +7. **Validation**: How to confirm the skill worked correctly +8. **Common Pitfalls**: Known traps and how to avoid them + +### Step 5: Add and populate optional directories if needed + +``` +.agents/skills// +├── 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 +- [ ] 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 | + +## 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..b2b2935b9e4 --- /dev/null +++ b/.agents/skills/migrations/SKILL.md @@ -0,0 +1,37 @@ +--- +name: migrations +description: 'EF Core migrations, migration scaffolding, MigrationsSqlGenerator, model diffing, migration operations, HistoryRepository, Migrator. Use when working on migrations add, database update, or migration SQL generation.' +user-invokable: false +--- + +# Migrations + +## Pipeline + +**Add migration**: `MigrationsScaffolder.ScaffoldMigration()` → `MigrationsModelDiffer.GetDifferences()` → list of `MigrationOperation` → `CSharpMigrationsGenerator` produces Up/Down/Snapshot code + +**Apply migration**: `Migrator.MigrateAsync()` → reads `__EFMigrationsHistory` → per pending: `MigrationsSqlGenerator.Generate(operations)` → `MigrationCommandExecutor` executes + +## Key Files + +| Area | Path | +|------|------| +| Scaffolder | `src/EFCore.Design/Migrations/Design/MigrationsScaffolder.cs` | +| C# generator | `src/EFCore.Design/Migrations/Design/CSharpMigrationsGenerator.cs` | +| Operation generator | `src/EFCore.Design/Migrations/Design/CSharpMigrationOperationGenerator.cs` | +| Snapshot generator | `src/EFCore.Design/Migrations/Design/CSharpSnapshotGenerator.cs` | +| SQL generator | `src/EFCore.Relational/Migrations/MigrationsSqlGenerator.cs` | +| Model differ | `src/EFCore.Relational/Migrations/Internal/MigrationsModelDiffer.cs` | +| History | `src/EFCore.Relational/Migrations/HistoryRepository.cs` | +| Operations | `src/EFCore.Relational/Migrations/Operations/` | + +Provider overrides: `SqlServerMigrationsSqlGenerator`, `SqliteMigrationsSqlGenerator` + +## 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`. + +## Validation + +- Generated migration code compiles and produces correct SQL +- `dotnet ef migrations script` output matches expected DDL diff --git a/.agents/skills/model-building/SKILL.md b/.agents/skills/model-building/SKILL.md new file mode 100644 index 00000000000..c6603bc8716 --- /dev/null +++ b/.agents/skills/model-building/SKILL.md @@ -0,0 +1,91 @@ + --- +name: model-building +description: 'EF Core model building, conventions, metadata interfaces, model initialization, runtime annotations, RuntimeModelConvention. Use when working on ConventionSet, ModelBuilder, IConvention implementations, ModelRuntimeInitializer, or RuntimeModel.' +user-invokable: false +--- + +# Model Building, Conventions & Initialization + +Covers model construction (conventions, fluent API, metadata hierarchy) and model initialization (runtime annotation propagation, compiled model filtering). + +## When to Use + +- Adding or modifying a convention +- Changing the fluent API or metadata builders +- Adding a new model-level annotation +- Working on `ModelRuntimeInitializer`, `RuntimeModelConvention`, or compiled model annotation filtering +- Understanding the `IReadOnly*` → `IMutable*` → `IConvention*` → `IRuntime*` interface hierarchy + +## Convention System + +`ConventionSet` (`src/EFCore/Metadata/Conventions/ConventionSet.cs`) holds `List` for every metadata event. Key conventions in `src/EFCore/Metadata/Conventions/`: + +- `DbSetFindingConvention` — discovers entities from `DbSet` +- `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. + +## Other Key Files + +- `src/EFCore/ModelBuilder.cs` — fluent API entry point +- `src/EFCore/Metadata/Internal/Model.cs` — mutable model +- `src/EFCore/Metadata/RuntimeModel.cs` — runtime model + +## 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` diff --git a/.agents/skills/query-pipeline/SKILL.md b/.agents/skills/query-pipeline/SKILL.md new file mode 100644 index 00000000000..9e330c8c541 --- /dev/null +++ b/.agents/skills/query-pipeline/SKILL.md @@ -0,0 +1,62 @@ +--- +name: query-pipeline +description: 'EF Core LINQ query translation, compilation, SQL generation, shaper, materialization. Use when working on query translation, expression visitors, SqlExpressions, QuerySqlGenerator, or ShaperProcessingExpressionVisitor.' +user-invokable: false +--- + +# Query Pipeline + +Translates LINQ expressions into database queries and materializes results. + +## When to Use + +- Adding or modifying query translation for a LINQ operator +- Adding a new SQL expression type or method/member translator +- Debugging incorrect SQL generation or materialization +- Working on the shaper, JSON column handling, or split queries + +## Stages + +1. **Preprocessing** — `QueryTranslationPreprocessor`: `NavigationExpandingExpressionVisitor` (Include, navigations, auto-includes), `QueryOptimizingExpressionVisitor` +2. **Translation** — `QueryableMethodTranslatingExpressionVisitor`: LINQ methods → `ShapedQueryExpression` (= `QueryExpression` + `ShaperExpression`). Relational: QueryExpression = `SelectExpression` +3. **Postprocessing** — `QueryTranslationPostprocessor`: `SqlNullabilityProcessor`, `SqlTreePruner`, `SqlAliasManager`, `RelationalParameterBasedSqlProcessor` +4. **Compilation** — `ShapedQueryCompilingExpressionVisitor` → executable delegate. Relational: `ShaperProcessingExpressionVisitor` builds materialization code + +Entry point: `QueryCompiler.CompileQueryCore()` → `QueryCompilationContext`. Result cached in `CompiledQueryCache`. + +## Key Files + +| Area | Path | +|------|------| +| Compilation context | `src/EFCore/Query/QueryCompilationContext.cs` | +| Navigation expansion | `src/EFCore/Query/Internal/NavigationExpandingExpressionVisitor.cs` | +| LINQ → SQL | `src/EFCore.Relational/Query/RelationalQueryableMethodTranslatingExpressionVisitor.cs` | +| C# → SQL expressions | `src/EFCore.Relational/Query/RelationalSqlTranslatingExpressionVisitor.cs` | +| SQL AST → string | `src/EFCore.Relational/Query/QuerySqlGenerator.cs` | +| Materialization | `src/EFCore.Relational/Query/RelationalShapedQueryCompilingExpressionVisitor.ShaperProcessingExpressionVisitor.cs` | +| SQL expression factory | `src/EFCore.Relational/Query/SqlExpressionFactory.cs` | +| SQL AST nodes | `src/EFCore.Relational/Query/SqlExpressions/` | +| ExecuteUpdate/Delete | partial files on `RelationalQueryableMethodTranslatingExpressionVisitor` | + +## Method/Member Translation + +Provider translators implement `IMethodCallTranslator` / `IMemberTranslator`, registered via the provider's `MethodCallTranslatorProvider`. Located in `src/EFCore.{Provider}/Query/Internal/Translators/`. + +Adding a new translator: +1. Implement `IMethodCallTranslator` — check `method.DeclaringType` before translating +2. Add to the provider's `*MethodCallTranslatorProvider` constructor's `AddTranslators()` call +3. Check the base relational layer first — common translations (e.g., `Math.Max`) may already exist + +## Cosmos Pipeline + +Parallel pipeline in `src/EFCore.Cosmos/Query/Internal/`: `CosmosQueryableMethodTranslatingExpressionVisitor`, `CosmosSqlTranslatingExpressionVisitor`, `CosmosQuerySqlGenerator`. Uses `JObject` materialization. Does not use any relational query infrastructure. + +## Testing + +Query specification tests: `test/EFCore.Specification.Tests/Query/`, `test/EFCore.Relational.Specification.Tests/Query/`. Provider overrides in `test/EFCore.{Provider}.FunctionalTests/Query/` with `AssertSql()` baselines. + +## 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..31f62056c4d --- /dev/null +++ b/.agents/skills/scaffolding/SKILL.md @@ -0,0 +1,42 @@ +--- +name: scaffolding +description: 'EF Core scaffolding (reverse engineering), CSharpModelGenerator, database schema reading, code generation. Use when working on ef dbcontext scaffold.' +user-invokable: false +--- + +# Scaffoldin + +Generates C# code from database schemas (reverse engineering). + +## When to Use + +- Modifying how `dotnet ef dbcontext scaffold` generates code +- Changing how database schemas are read by a provider's `IDatabaseModelFactory` + +## 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#) + +Key files in `src/EFCore.Design/Scaffolding/`: +- `IReverseEngineerScaffolder` — orchestrates full pipeline +- `Internal/CSharpModelGenerator.cs` — default C# generator + +Provider factories: `SqlServerDatabaseModelFactory`, `SqliteDatabaseModelFactory` + + +## Design-Time Services + +`IDesignTimeServices` — provider/plugin registers design-time services. `DesignTimeServicesBuilder` discovers them. + +## Testing + +Scaffolding tests: `test/EFCore.Design.Tests/Scaffolding/`. + +## Validation + +- Compiled model baselines in `Baselines/{testName}/` directories +- `EF_TEST_REWRITE_BASELINES=1` auto-updates baselines diff --git a/.agents/skills/servicing-pr/SKILL.md b/.agents/skills/servicing-pr/SKILL.md new file mode 100644 index 00000000000..328e16b17b1 --- /dev/null +++ b/.agents/skills/servicing-pr/SKILL.md @@ -0,0 +1,70 @@ +--- +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, 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. + +## When to Use + +- Creating a PR that targets a `release/*` branch +- Backporting a fix from `main` to a servicing branch + +## 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] ` + +## 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 workaround. + +**How found** +How the bug was discovered based on the information in the issue description. If user-reported, mention "User reported on ". 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..2ae5913b0c1 --- /dev/null +++ b/.agents/skills/sqlite-adonet/SKILL.md @@ -0,0 +1,40 @@ +--- +name: sqlite-adonet +description: 'Microsoft.Data.Sqlite ADO.NET provider for SQLite. Use when working on SqliteConnection, SqliteCommand, SqliteDataReader, connection pooling, user-defined functions, or SQLite-specific ADO.NET functionality.' +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. + +## When to Use + +- Working on SQLite connection, command, or data reader behavior +- Modifying connection pooling logic +- Adding or changing user-defined function registration +- Debugging SQLite-specific data type handling + +## Key Classes + +| Class | Purpose | +|-------|---------| +| `SqliteConnection` | Connection lifecycle, `CreateFunction`/`CreateAggregate` | +| `SqliteCommand` | SQL execution, prepared statements | +| `SqliteDataReader` | Result set reading | +| `SqliteConnectionPool` | Warm/cold pool stacks, prune timer (2-4 min interval) | +| `SqliteConnectionPoolGroup` | Groups pools by connection string | +| `SqliteBlob` | Streaming blob I/O via `sqlite3_blob_*` APIs | + +## Notable Implementation Details + +- Static constructor calls `SQLitePCL.Batteries_V2.Init()` reflectively +- Connection pooling is opt-in (`Pooling=True` in connection string) +- `CreateFunction()`/`CreateAggregate()` overloads generated from T4 templates (`.tt` files) +- Core implementation: `CreateFunctionCore` wraps .NET delegates into SQLitePCL callbacks +- No true async I/O — async methods are sync wrappers +- File-based or `Data Source=:memory:` for in-memory databases + +## Testing + +Tests in `test/Microsoft.Data.Sqlite.Tests/`. diff --git a/.agents/skills/testing/SKILL.md b/.agents/skills/testing/SKILL.md new file mode 100644 index 00000000000..da81d002a4e --- /dev/null +++ b/.agents/skills/testing/SKILL.md @@ -0,0 +1,85 @@ +--- +name: testing +description: 'EF Core test infrastructure, debugging failing tests, writing new tests, SQL baseline assertions, fixtures, test helpers. Use when adding tests, debugging test failures, fixing SQL baselines, or understanding the test class hierarchy.' +user-invokable: false +--- + +# Testing + +EF Core test infrastructure, patterns, and workflows for unit, specification, and functional tests. + +## When to Use + +- Adding new unit or functional tests +- Debugging test failures (model validation, SQL or compiled model baseline mismatch) +- Understanding which test project and base class to use + +## 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 # Core + └─ NorthwindWhereQueryTestBase # Specification + └─ NorthwindWhereQueryRelationalTestBase # 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 +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(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..f5f017c4e92 --- /dev/null +++ b/.agents/skills/tooling/SKILL.md @@ -0,0 +1,59 @@ +--- +name: tooling +description: 'EF Core dotnet-ef CLI tool, Package Manager Console commands, EFCore.Tools PowerShell module, EFCore.Tasks MSBuild integration. Use when working on dotnet-ef commands, the ef wrapper, or tool infrastructure.' +user-invokable: false +--- + +# Tooling + +The `dotnet ef` CLI and Visual Studio Package Manager Console commands for migrations, scaffolding, and compiled models. + +## When to Use + +- Adding or modifying a `dotnet ef` command +- Working on PMC (PowerShell) command wrappers +- Debugging tool invocation, project discovery, or MSBuild integration + +## 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 runs `OperationExecutor` in-process. + +## 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. + +### Key Classes + +- `OptimizeDbContext` — public MSBuild task. Invokes `dotnet exec ef.dll dbcontext optimize`, collects generated `.g.cs` files as `[Output]` +- `OperationTaskBase` — abstract base extending `ToolTask`. Orchestrates `dotnet exec ef.dll` with assembly/deps/runtimeconfig args. Parses prefixed output into MSBuild errors/warnings + +### Build Properties (user-configurable in `.csproj`) + +| Property | Default | Purpose | +|----------|---------|--------| +| `EFOptimizeContext` | unset | `true` enables generation outside NativeAOT publish | +| `EFScaffoldModelStage` | `publish` | `publish` or `build` — when to generate compiled model | +| `EFPrecompileQueriesStage` | `publish` | `publish` or `build` — when to precompile queries | +| `DbContextType` | `*` | Specific `DbContext` to optimize, `*` = all | +| `EFOutputDir` | `$(IntermediateOutputPath)` | Directory for generated files | + +### 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 diff --git a/.agents/skills/update-pipeline/SKILL.md b/.agents/skills/update-pipeline/SKILL.md new file mode 100644 index 00000000000..c261d61bf84 --- /dev/null +++ b/.agents/skills/update-pipeline/SKILL.md @@ -0,0 +1,55 @@ +--- +name: update-pipeline +description: 'EF Core SaveChanges, modification commands, command batching, update SQL generation, stored procedure updates. Use when working on the update pipeline, CommandBatchPreparer, UpdateSqlGenerator, or ModificationCommand.' +user-invokable: false +--- + +# Update Pipeline + +Converts tracked entity changes into database INSERT/UPDATE/DELETE commands during `SaveChanges()`. + +## When to Use + +- Modifying how changes are batched or ordered +- Working on SQL generation for INSERT/UPDATE/DELETE +- Handling store-generated values (identity, computed columns) +- Debugging concurrency or transaction issues in SaveChanges + +## Flow + +``` +SaveChanges() → DetectChanges() → IDatabase.SaveChanges() + → UpdateAdapter creates IUpdateEntry list + → CommandBatchPreparer.BatchCommands() + → ModificationCommand per entity (maps to table row) + → 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() +``` + +## Key Files + +| Area | Path | +|------|------| +| Batch preparation | `src/EFCore.Relational/Update/Internal/CommandBatchPreparer.cs` | +| Modification command | `src/EFCore.Relational/Update/ModificationCommand.cs` | +| Column modification | `src/EFCore.Relational/Update/ColumnModification.cs` | +| SQL generation | `src/EFCore.Relational/Update/UpdateSqlGenerator.cs` | +| Batch execution | `src/EFCore.Relational/Update/Internal/BatchExecutor.cs` | +| Shared tables | `src/EFCore.Relational/Update/Internal/SharedTableEntryMap.cs` | + +## Concurrency + +Concurrency tokens → WHERE conditions on UPDATE/DELETE. `AffectedCountModificationCommandBatch` checks affected rows. Throws `DbUpdateConcurrencyException` on mismatch. + +## Testing + +Update specification tests: `test/EFCore.Relational.Specification.Tests/Update/`. + +## 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. From 17fc6611de3dd991a65fc969b4d94859b68e65e5 Mon Sep 17 00:00:00 2001 From: Andriy Svyryd Date: Sat, 21 Feb 2026 19:32:16 -0800 Subject: [PATCH 02/14] Update .agents/skills/scaffolding/SKILL.md Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .agents/skills/scaffolding/SKILL.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.agents/skills/scaffolding/SKILL.md b/.agents/skills/scaffolding/SKILL.md index 31f62056c4d..62f672e2d9b 100644 --- a/.agents/skills/scaffolding/SKILL.md +++ b/.agents/skills/scaffolding/SKILL.md @@ -4,7 +4,7 @@ description: 'EF Core scaffolding (reverse engineering), CSharpModelGenerator, d user-invokable: false --- -# Scaffoldin +# Scaffolding Generates C# code from database schemas (reverse engineering). From c1b2187555fb6a13ba081cdf96991cf54823527b Mon Sep 17 00:00:00 2001 From: Andriy Svyryd Date: Sat, 21 Feb 2026 19:33:05 -0800 Subject: [PATCH 03/14] Update .agents/skills/model-building/SKILL.md Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .agents/skills/model-building/SKILL.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.agents/skills/model-building/SKILL.md b/.agents/skills/model-building/SKILL.md index c6603bc8716..7f8ee4bbbf8 100644 --- a/.agents/skills/model-building/SKILL.md +++ b/.agents/skills/model-building/SKILL.md @@ -1,4 +1,4 @@ - --- +--- name: model-building description: 'EF Core model building, conventions, metadata interfaces, model initialization, runtime annotations, RuntimeModelConvention. Use when working on ConventionSet, ModelBuilder, IConvention implementations, ModelRuntimeInitializer, or RuntimeModel.' user-invokable: false From a25566d09b85eeeba9e2f07375fb1819c00dfde3 Mon Sep 17 00:00:00 2001 From: Andriy Svyryd Date: Sat, 21 Feb 2026 19:33:28 -0800 Subject: [PATCH 04/14] Update .agents/skills/make-skill/SKILL.md Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .agents/skills/make-skill/SKILL.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.agents/skills/make-skill/SKILL.md b/.agents/skills/make-skill/SKILL.md index 809df28c60f..c5322f935a7 100644 --- a/.agents/skills/make-skill/SKILL.md +++ b/.agents/skills/make-skill/SKILL.md @@ -27,7 +27,7 @@ This skill helps you scaffold new agent skills that conform to the Agent Skills ### Step 1: Investigate the Topic -Build deep understanding of the relevant topics using. +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 From 5c6919514672ca5d5b4507f6ed6571dcae6fe6de Mon Sep 17 00:00:00 2001 From: Andriy Svyryd Date: Sat, 21 Feb 2026 19:33:43 -0800 Subject: [PATCH 05/14] Update .agents/skills/make-skill/SKILL.md Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .agents/skills/make-skill/SKILL.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.agents/skills/make-skill/SKILL.md b/.agents/skills/make-skill/SKILL.md index c5322f935a7..ab2c884b732 100644 --- a/.agents/skills/make-skill/SKILL.md +++ b/.agents/skills/make-skill/SKILL.md @@ -38,7 +38,7 @@ After investigating, verify: - [ ] 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 would be better handled by a custom agent, agentic workflow, an existing skill or multiple narrower skills, and discuss this with the user if relevant. +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 From 466380d647e33549bda40583c90a79640f51ccd9 Mon Sep 17 00:00:00 2001 From: Andriy Svyryd Date: Sat, 21 Feb 2026 19:33:53 -0800 Subject: [PATCH 06/14] Update .agents/skills/scaffolding/SKILL.md Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .agents/skills/scaffolding/SKILL.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.agents/skills/scaffolding/SKILL.md b/.agents/skills/scaffolding/SKILL.md index 62f672e2d9b..27650ba5283 100644 --- a/.agents/skills/scaffolding/SKILL.md +++ b/.agents/skills/scaffolding/SKILL.md @@ -13,7 +13,7 @@ Generates C# code from database schemas (reverse engineering). - Modifying how `dotnet ef dbcontext scaffold` generates code - Changing how database schemas are read by a provider's `IDatabaseModelFactory` -## When not to Use +## When Not to Use - Working on compiled model generation (`dotnet ef dbcontext optimize`) From 1da7498939f286972c8a560a23c8f58e2ab83af7 Mon Sep 17 00:00:00 2001 From: Andriy Svyryd Date: Sat, 21 Feb 2026 19:34:06 -0800 Subject: [PATCH 07/14] Update .agents/skills/servicing-pr/SKILL.md Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .agents/skills/servicing-pr/SKILL.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.agents/skills/servicing-pr/SKILL.md b/.agents/skills/servicing-pr/SKILL.md index 328e16b17b1..b1bbf10548b 100644 --- a/.agents/skills/servicing-pr/SKILL.md +++ b/.agents/skills/servicing-pr/SKILL.md @@ -32,7 +32,7 @@ Backports #{source_pr_number_if_applicable} 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 workaround. +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 ". If multiple users are affected, note that. Count the number of upvotes and comment authors to estimate impact. From 6df01ca8ebbcffcf2d07ff8b647342d7b8c2c416 Mon Sep 17 00:00:00 2001 From: Andriy Svyryd Date: Sun, 22 Feb 2026 00:44:17 -0800 Subject: [PATCH 08/14] Update .agents/skills/dbcontext-and-services/SKILL.md Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .agents/skills/dbcontext-and-services/SKILL.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.agents/skills/dbcontext-and-services/SKILL.md b/.agents/skills/dbcontext-and-services/SKILL.md index 288d9ff8c5c..13ef0cb49e0 100644 --- a/.agents/skills/dbcontext-and-services/SKILL.md +++ b/.agents/skills/dbcontext-and-services/SKILL.md @@ -17,7 +17,7 @@ EF Core's internal DI container, service registration, and context lifecycle man ## Service Registration -`EntityFrameworkServicesBuilder` (`src/EFCore/Infrastructure/EntityFrameworkServicesBuilder.cs`, 531 lines) maintains a `CoreServices` dictionary mapping service types to `ServiceCharacteristics` (lifetime + multi-registration flag). `TryAddCoreServices()` registers ~60+ services. +`EntityFrameworkServicesBuilder` (`src/EFCore/Infrastructure/EntityFrameworkServicesBuilder.cs`) maintains a `CoreServices` dictionary mapping service types to `ServiceCharacteristics` (lifetime + multi-registration flag). `TryAddCoreServices()` registers ~60+ services. Pattern: Providers call `TryAddProviderSpecificServices()` first, then `TryAddCoreServices()` fills remaining defaults. From b1ccc523378329b6180168b44aabd81ed3da6a87 Mon Sep 17 00:00:00 2001 From: Andriy Svyryd Date: Sun, 22 Feb 2026 00:45:29 -0800 Subject: [PATCH 09/14] Update .agents/skills/tooling/SKILL.md Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .agents/skills/tooling/SKILL.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.agents/skills/tooling/SKILL.md b/.agents/skills/tooling/SKILL.md index f5f017c4e92..282a98fe0b6 100644 --- a/.agents/skills/tooling/SKILL.md +++ b/.agents/skills/tooling/SKILL.md @@ -16,7 +16,7 @@ The `dotnet ef` CLI and Visual Studio Package Manager Console commands for migra ## 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 runs `OperationExecutor` in-process. +`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/`) From cf2527045aa93215abef157e2a4031c26c87fd9b Mon Sep 17 00:00:00 2001 From: Andriy Svyryd Date: Sun, 22 Feb 2026 00:47:02 -0800 Subject: [PATCH 10/14] Update .agents/skills/analyzers/SKILL.md --- .agents/skills/analyzers/SKILL.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.agents/skills/analyzers/SKILL.md b/.agents/skills/analyzers/SKILL.md index 465199020ef..545a727428e 100644 --- a/.agents/skills/analyzers/SKILL.md +++ b/.agents/skills/analyzers/SKILL.md @@ -25,7 +25,7 @@ Roslyn analyzers shipped in `Microsoft.EntityFrameworkCore.Analyzers` (`src/EFCo ## Testing -Tests in `test/EFCore.Analyzers.Tests/` use `CSharpAnalyzerVerifier`. Test methods provide inline C# source with diagnostic location markers. Pattern: +Tests in `test/EFCore.Analyzers.Tests/` use `CSharpAnalyzerVerifier`. Test methods provide inline C# source with diagnostic location markers. ## Validation From 5bfd03a15edfd4205cf786214d56697ff11e68ed Mon Sep 17 00:00:00 2001 From: Andriy Svyryd Date: Sun, 22 Feb 2026 14:15:37 -0800 Subject: [PATCH 11/14] React to PR feedback --- .agents/skills/analyzers/SKILL.md | 13 +-- .agents/skills/bulk-operations/SKILL.md | 17 +-- .agents/skills/change-tracking/SKILL.md | 27 +---- .agents/skills/cosmos-provider/SKILL.md | 15 +-- .../skills/dbcontext-and-services/SKILL.md | 15 +-- .agents/skills/make-instructions/SKILL.md | 100 ++++++++++++++++++ .agents/skills/make-skill/SKILL.md | 4 + .agents/skills/migrations/SKILL.md | 10 +- .agents/skills/model-building/SKILL.md | 1 + .agents/skills/query-pipeline/SKILL.md | 4 - .agents/skills/scaffolding/SKILL.md | 6 -- .agents/skills/sqlite-adonet/SKILL.md | 4 - .agents/skills/tooling/SKILL.md | 1 + .agents/skills/update-pipeline/SKILL.md | 29 ++--- 14 files changed, 134 insertions(+), 112 deletions(-) create mode 100644 .agents/skills/make-instructions/SKILL.md diff --git a/.agents/skills/analyzers/SKILL.md b/.agents/skills/analyzers/SKILL.md index 545a727428e..db15098372a 100644 --- a/.agents/skills/analyzers/SKILL.md +++ b/.agents/skills/analyzers/SKILL.md @@ -16,19 +16,10 @@ Roslyn analyzers shipped in `Microsoft.EntityFrameworkCore.Analyzers` (`src/EFCo ## Analyzers -| ID | Analyzer | Category | Purpose | -|----|----------|----------|---------| -| EF1001 | `InternalUsageDiagnosticAnalyzer` (333 lines) | Usage | Warns on `.Internal` namespace / `[EntityFrameworkInternal]` usage. Registers operation + symbol actions for field, property, method, event, invocation, object creation, variable declaration, typeof, named type. | -| EF1002 | `StringsUsageInRawQueriesDiagnosticAnalyzer` (254 lines) | Security | Two diagnostics: interpolated string usage and string concatenation in raw SQL methods. Registers `OperationKind.Invocation` action. | -| — | `InterpolatedStringUsageInRawQueriesCodeFixProvider` | — | Fix for EF1002: `FromSqlRaw` → `FromSqlInterpolated` | -| — | `UninitializedDbSetDiagnosticSuppressor` | — | Suppresses CS8618 for `DbSet` properties on `DbContext` | - -## Testing - -Tests in `test/EFCore.Analyzers.Tests/` use `CSharpAnalyzerVerifier`. Test methods provide inline C# source with diagnostic location markers. +See AnalyzerReleases.Shipped.md for a complete list of shipped diagnostics. ## Validation -- Analyzer triggers on expected code patterns +- Analyzer triggers on expected code patterns in an efficient manner - No false positives on public API usage - Code fix produces compilable output diff --git a/.agents/skills/bulk-operations/SKILL.md b/.agents/skills/bulk-operations/SKILL.md index 1767d300778..d53a517a701 100644 --- a/.agents/skills/bulk-operations/SKILL.md +++ b/.agents/skills/bulk-operations/SKILL.md @@ -21,24 +21,9 @@ user-invokable: false - Public API: `EntityFrameworkQueryableExtensions` — `ExecuteDelete`, `ExecuteUpdate` + async - Setters: `SetPropertyCalls.cs`, `UpdateSettersBuilder.cs` -## Unsupported Scenarios - -These throw at translation time — know them before attempting changes: - -| Scenario | Error | -|----------|-------| -| TPC (non-leaf types) | `ExecuteOperationOnTPC` | -| TPT (ExecuteDelete) | `ExecuteOperationOnTPT` | -| JSON-mapped owned entities | `ExecuteOperationOnOwnedJsonIsNotSupported` | -| JSON-mapped complex types | `ExecuteUpdateOverJsonIsNotSupported` | -| Complex types in subqueries | `ExecuteUpdateSubqueryNotSupportedOverComplexTypes` | -| Keyless entities | `ExecuteOperationOnKeylessEntityTypeWithUnsupportedOperator` | -| Entity splitting (Delete) | `ExecuteOperationOnEntitySplitting` | -| Table splitting (Delete) | `ExecuteDeleteOnTableSplitting` | - ## Testing -Specification tests: `test/EFCore.Specification.Tests/BulkUpdates/NorthwindBulkUpdatesTestBase.cs`. Uses `AssertDelete(async, query, rowsAffectedCount)` / `AssertUpdate(...)`. Provider overrides in `test/EFCore.{Provider}.FunctionalTests/BulkUpdates/` with `AssertSql()` baselines. +Specification tests: `test/EFCore.Specification.Tests/BulkUpdates/`. Provider overrides in `test/EFCore.{Provider}.FunctionalTests/BulkUpdates/`. ## Validation diff --git a/.agents/skills/change-tracking/SKILL.md b/.agents/skills/change-tracking/SKILL.md index 5964010fe9b..829f6f7a245 100644 --- a/.agents/skills/change-tracking/SKILL.md +++ b/.agents/skills/change-tracking/SKILL.md @@ -24,34 +24,18 @@ Manages entity states and detects changes for `SaveChanges()`. ## Snapshots -Built by `SnapshotFactoryFactory` subclasses via compiled expression trees: -- `OriginalValuesFactoryFactory` — for detecting property changes -- `RelationshipSnapshotFactoryFactory` — for FK/navigation fix-up +Built by `SnapshotFactoryFactory` subclasses via compiled expression trees. ## Property Accessors Compiled expression trees in `PropertyAccessorsFactory`: -- `CreateMemberAccess()` — entity → complex property → nested property -- `CreateComplexCollectionElementAccess()` — entity → collection → element[ordinal] → property -- Ordinals in `indices` parameter specify element at each collection depth -- Guard expressions added when `DetailedErrorsEnabled` annotation is set on the model +- Ordinals in `indices` parameter specify element at each complex collection depth -Getters compiled lazily via `ClrPropertyGetterFactory` → `ClrPropertyGetter`. Two delegates: -- `GetClrValue(instance)` — from immediate declaring object -- `GetClrValueUsingContainingEntity(entity, indices)` — from root entity through complex chain - -## Key Files - -- `src/EFCore/ChangeTracking/Internal/StateManager.cs` -- `src/EFCore/ChangeTracking/Internal/InternalEntityEntry.cs` -- `src/EFCore/ChangeTracking/Internal/ChangeDetector.cs` -- `src/EFCore/Metadata/Internal/PropertyAccessorsFactory.cs` -- `src/EFCore/Metadata/Internal/ClrPropertyGetterFactory.cs` -- `src/EFCore/ChangeTracking/Internal/SnapshotFactoryFactory.cs` +Getters and setterscompiled lazily via `ClrPropertyGetterFactory` ands `ClrPropertySetterFactory`. ## Testing -Unit tests: `test/EFCore.Tests/ChangeTracking/`. Functional tests: `test/EFCore.{Provider}.FunctionalTests/`. +Unit tests: `test/EFCore.Tests/ChangeTracking/`. Functional tests: `test/EFCore.Specification.Tests/GraphUpdates/`. ## Common Pitfalls @@ -61,6 +45,5 @@ Unit tests: `test/EFCore.Tests/ChangeTracking/`. Functional tests: `test/EFCore. ## Validation -- Entity states transition correctly (`Added` → `Unchanged` after save, etc.) - `DetectChanges()` identifies modified properties via snapshot comparison -- Property accessor expression trees compile without errors at runtime +- 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 index 15016f0d730..448784b5791 100644 --- a/.agents/skills/cosmos-provider/SKILL.md +++ b/.agents/skills/cosmos-provider/SKILL.md @@ -10,20 +10,18 @@ Non-relational provider with its own parallel query pipeline. Uses JSON for docu ## When to Use -- Adding or modifying Cosmos query translation +- Working on Cosmos SQL generation - Working on document storage, partition key configuration, or `CosmosClientWrapper` -- Debugging Cosmos SQL generation differences from relational SQL ## Key Differences from Relational - No migrations — use `EnsureCreated()` -- Documents as JSON — owned types become embedded objects +- Documents as JSON — owned and complex types become embedded objects - Partition key configuration required for performance -- Limited query translation (more client evaluation) - `ETag` for optimistic concurrency - No cross-container joins -## Key Files +## Other Key Files | Area | Path | |------|------| @@ -31,12 +29,7 @@ Non-relational provider with its own parallel query pipeline. Uses JSON for docu | Expression → Cosmos SQL | `src/EFCore.Cosmos/Query/Internal/CosmosSqlTranslatingExpressionVisitor.cs` | | SQL generation | `src/EFCore.Cosmos/Query/Internal/CosmosQuerySqlGenerator.cs` | | Compilation | `src/EFCore.Cosmos/Query/Internal/CosmosShapedQueryCompilingExpressionVisitor.cs` | -| Cosmos SDK wrapper | `src/EFCore.Cosmos/Storage/Internal/CosmosClientWrapper.cs` | -| SQL AST nodes | `src/EFCore.Cosmos/Query/Internal/Expressions/` (~33 expression types) | - -## Testing - -Unit tests: `test/EFCore.Cosmos.Tests/`. Functional tests: `test/EFCore.Cosmos.FunctionalTests/`. +| SQL AST nodes | `src/EFCore.Cosmos/Query/Internal/Expressions/` | ## Validation diff --git a/.agents/skills/dbcontext-and-services/SKILL.md b/.agents/skills/dbcontext-and-services/SKILL.md index 13ef0cb49e0..38d126edecc 100644 --- a/.agents/skills/dbcontext-and-services/SKILL.md +++ b/.agents/skills/dbcontext-and-services/SKILL.md @@ -17,9 +17,9 @@ EF Core's internal DI container, service registration, and context lifecycle man ## Service Registration -`EntityFrameworkServicesBuilder` (`src/EFCore/Infrastructure/EntityFrameworkServicesBuilder.cs`) maintains a `CoreServices` dictionary mapping service types to `ServiceCharacteristics` (lifetime + multi-registration flag). `TryAddCoreServices()` registers ~60+ services. +`EntityFrameworkServicesBuilder` maintains a `CoreServices` dictionary mapping service types to `ServiceCharacteristics` (lifetime + multi-registration flag). -Pattern: Providers call `TryAddProviderSpecificServices()` first, then `TryAddCoreServices()` fills remaining defaults. +Pattern: Providers call `TryAddProviderSpecificServices()` first, then `TryAddCoreServices()` fills remaining services without overriding existing registrations. ## Dependencies Pattern @@ -28,21 +28,16 @@ Services receive dependencies via sealed records (not constructor injection of i public sealed record MyServiceDependencies(IDep1 Dep1, IDep2 Dep2); ``` -## DbContext Pooling - -`DbContextPool` uses `ConcurrentQueue`. Default pool size: 1024. Set via `CoreOptionsExtension.MaxPoolSize`. Options are frozen at pool creation. - -## Key Files +## Other Key Files - `src/EFCore/DbContext.cs` — main context, implements `IDbContextPoolable` - `src/EFCore/Infrastructure/DbContextOptions.cs` — immutable sorted dictionary of `IDbContextOptionsExtension` -- `src/EFCore/Infrastructure/EntityFrameworkServicesBuilder.cs` — service registration - `src/EFCore/Internal/DbContextServices.cs` — scoped service resolver, model creation, provider validation -- `src/EFCore/Internal/DbContextPool.cs` — pooling implementation +- `src/EFCore/Internal/DbContextPool.cs` — manages a pool of `IDbContextPoolable` instances. Options are frozen at pool creation. ## Testing -Unit tests: `test/EFCore.Tests/` (e.g., `DbContextTest.cs`, `EntityFrameworkServiceCollectionExtensionsTest.cs`). +Unit tests: `DbContextTest.cs`, `EntityFrameworkServiceCollectionExtensionsTest.cs`. ## Validation diff --git a/.agents/skills/make-instructions/SKILL.md b/.agents/skills/make-instructions/SKILL.md new file mode 100644 index 00000000000..d61091bae4a --- /dev/null +++ b/.agents/skills/make-instructions/SKILL.md @@ -0,0 +1,100 @@ +--- +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 to Use + +- Creating a new `.instructions.md` file from scratch +- Adding language-specific, framework-specific, or module-specific coding guidelines +- Providing background knowledge about a subsystem that Copilot should consider when editing 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 index ab2c884b732..8a0b8213e30 100644 --- a/.agents/skills/make-skill/SKILL.md +++ b/.agents/skills/make-skill/SKILL.md @@ -15,6 +15,7 @@ This skill helps you scaffold new agent skills that conform to the Agent Skills ## 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 @@ -100,6 +101,7 @@ After creating a skill, verify: - [ ] 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 @@ -115,6 +117,8 @@ After creating a skill, verify: | 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 diff --git a/.agents/skills/migrations/SKILL.md b/.agents/skills/migrations/SKILL.md index b2b2935b9e4..1490719cca5 100644 --- a/.agents/skills/migrations/SKILL.md +++ b/.agents/skills/migrations/SKILL.md @@ -8,20 +8,15 @@ user-invokable: false ## Pipeline -**Add migration**: `MigrationsScaffolder.ScaffoldMigration()` → `MigrationsModelDiffer.GetDifferences()` → list of `MigrationOperation` → `CSharpMigrationsGenerator` produces Up/Down/Snapshot code +**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 -## Key Files +## Other Key Files | Area | Path | |------|------| -| Scaffolder | `src/EFCore.Design/Migrations/Design/MigrationsScaffolder.cs` | -| C# generator | `src/EFCore.Design/Migrations/Design/CSharpMigrationsGenerator.cs` | | Operation generator | `src/EFCore.Design/Migrations/Design/CSharpMigrationOperationGenerator.cs` | -| Snapshot generator | `src/EFCore.Design/Migrations/Design/CSharpSnapshotGenerator.cs` | -| SQL generator | `src/EFCore.Relational/Migrations/MigrationsSqlGenerator.cs` | -| Model differ | `src/EFCore.Relational/Migrations/Internal/MigrationsModelDiffer.cs` | | History | `src/EFCore.Relational/Migrations/HistoryRepository.cs` | | Operations | `src/EFCore.Relational/Migrations/Operations/` | @@ -34,4 +29,3 @@ Migration operation tests: `test/EFCore.Relational.Tests/Migrations/`. Functiona ## Validation - Generated migration code compiles and produces correct SQL -- `dotnet ef migrations script` output matches expected DDL diff --git a/.agents/skills/model-building/SKILL.md b/.agents/skills/model-building/SKILL.md index 7f8ee4bbbf8..6d044b2a53f 100644 --- a/.agents/skills/model-building/SKILL.md +++ b/.agents/skills/model-building/SKILL.md @@ -89,3 +89,4 @@ Created lazily by `RelationalModelRuntimeInitializer`, accessed via `model.GetRe - 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 diff --git a/.agents/skills/query-pipeline/SKILL.md b/.agents/skills/query-pipeline/SKILL.md index 9e330c8c541..1758e319d28 100644 --- a/.agents/skills/query-pipeline/SKILL.md +++ b/.agents/skills/query-pipeline/SKILL.md @@ -51,10 +51,6 @@ Adding a new translator: Parallel pipeline in `src/EFCore.Cosmos/Query/Internal/`: `CosmosQueryableMethodTranslatingExpressionVisitor`, `CosmosSqlTranslatingExpressionVisitor`, `CosmosQuerySqlGenerator`. Uses `JObject` materialization. Does not use any relational query infrastructure. -## Testing - -Query specification tests: `test/EFCore.Specification.Tests/Query/`, `test/EFCore.Relational.Specification.Tests/Query/`. Provider overrides in `test/EFCore.{Provider}.FunctionalTests/Query/` with `AssertSql()` baselines. - ## Validation - `ToQueryString()` shows generated SQL without executing diff --git a/.agents/skills/scaffolding/SKILL.md b/.agents/skills/scaffolding/SKILL.md index 27650ba5283..c584b6f5cdb 100644 --- a/.agents/skills/scaffolding/SKILL.md +++ b/.agents/skills/scaffolding/SKILL.md @@ -27,7 +27,6 @@ Key files in `src/EFCore.Design/Scaffolding/`: Provider factories: `SqlServerDatabaseModelFactory`, `SqliteDatabaseModelFactory` - ## Design-Time Services `IDesignTimeServices` — provider/plugin registers design-time services. `DesignTimeServicesBuilder` discovers them. @@ -35,8 +34,3 @@ Provider factories: `SqlServerDatabaseModelFactory`, `SqliteDatabaseModelFactory ## Testing Scaffolding tests: `test/EFCore.Design.Tests/Scaffolding/`. - -## Validation - -- Compiled model baselines in `Baselines/{testName}/` directories -- `EF_TEST_REWRITE_BASELINES=1` auto-updates baselines diff --git a/.agents/skills/sqlite-adonet/SKILL.md b/.agents/skills/sqlite-adonet/SKILL.md index 2ae5913b0c1..fd8dc15ac83 100644 --- a/.agents/skills/sqlite-adonet/SKILL.md +++ b/.agents/skills/sqlite-adonet/SKILL.md @@ -34,7 +34,3 @@ Standalone ADO.NET provider in `src/Microsoft.Data.Sqlite.Core/`, independent of - Core implementation: `CreateFunctionCore<TState, TResult>` wraps .NET delegates into SQLitePCL callbacks - No true async I/O — async methods are sync wrappers - File-based or `Data Source=:memory:` for in-memory databases - -## Testing - -Tests in `test/Microsoft.Data.Sqlite.Tests/`. diff --git a/.agents/skills/tooling/SKILL.md b/.agents/skills/tooling/SKILL.md index 282a98fe0b6..1e4f70a2cf2 100644 --- a/.agents/skills/tooling/SKILL.md +++ b/.agents/skills/tooling/SKILL.md @@ -57,3 +57,4 @@ Targets in `buildTransitive/Microsoft.EntityFrameworkCore.Tasks.targets`: ## 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 index c261d61bf84..ceb8d19c96d 100644 --- a/.agents/skills/update-pipeline/SKILL.md +++ b/.agents/skills/update-pipeline/SKILL.md @@ -17,37 +17,26 @@ Converts tracked entity changes into database INSERT/UPDATE/DELETE commands duri ## Flow -``` -SaveChanges() → DetectChanges() → IDatabase.SaveChanges() - → UpdateAdapter creates IUpdateEntry list - → CommandBatchPreparer.BatchCommands() - → ModificationCommand per entity (maps to table row) +`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() -``` + → Groups into `ModificationCommandBatch` (respects max batch size) + → `UpdateSqlGenerator` generates SQL per batch + → `BatchExecutor` executes all batches in a transaction + → `StateManager.AcceptAllChanges()` -## Key Files +## Other Key Files | Area | Path | |------|------| -| Batch preparation | `src/EFCore.Relational/Update/Internal/CommandBatchPreparer.cs` | -| Modification command | `src/EFCore.Relational/Update/ModificationCommand.cs` | -| Column modification | `src/EFCore.Relational/Update/ColumnModification.cs` | -| SQL generation | `src/EFCore.Relational/Update/UpdateSqlGenerator.cs` | -| Batch execution | `src/EFCore.Relational/Update/Internal/BatchExecutor.cs` | | Shared tables | `src/EFCore.Relational/Update/Internal/SharedTableEntryMap.cs` | ## Concurrency Concurrency tokens → WHERE conditions on UPDATE/DELETE. `AffectedCountModificationCommandBatch` checks affected rows. Throws `DbUpdateConcurrencyException` on mismatch. -## Testing - -Update specification tests: `test/EFCore.Relational.Specification.Tests/Update/`. - ## Validation - `SaveChanges()` returns expected affected row count From 717c7756c59a08c72df2fae077f23e3a0e0ed11f Mon Sep 17 00:00:00 2001 From: Andriy Svyryd <Andriy.Svyryd@microsoft.com> Date: Wed, 25 Feb 2026 16:04:08 -0800 Subject: [PATCH 12/14] Remove unneeded instructions --- .agents/skills/analyzers/SKILL.md | 24 +- .agents/skills/bulk-operations/SKILL.md | 28 +- .agents/skills/change-tracking/SKILL.md | 27 +- .agents/skills/cosmos-provider/SKILL.md | 16 +- .agents/skills/create-custom-agent/SKILL.md | 246 ++++++++++++++++++ .../skills/dbcontext-and-services/SKILL.md | 26 +- .agents/skills/make-instructions/SKILL.md | 6 - .agents/skills/make-skill/SKILL.md | 18 +- .agents/skills/migrations/SKILL.md | 18 +- .agents/skills/model-building/SKILL.md | 16 +- .agents/skills/query-pipeline/SKILL.md | 45 +--- .agents/skills/scaffolding/SKILL.md | 20 +- .agents/skills/servicing-pr/SKILL.md | 7 +- .agents/skills/sqlite-adonet/SKILL.md | 24 +- .agents/skills/testing/SKILL.md | 8 +- .agents/skills/tooling/SKILL.md | 23 +- .agents/skills/update-pipeline/SKILL.md | 16 +- 17 files changed, 278 insertions(+), 290 deletions(-) create mode 100644 .agents/skills/create-custom-agent/SKILL.md diff --git a/.agents/skills/analyzers/SKILL.md b/.agents/skills/analyzers/SKILL.md index db15098372a..8efbb40967e 100644 --- a/.agents/skills/analyzers/SKILL.md +++ b/.agents/skills/analyzers/SKILL.md @@ -1,25 +1,5 @@ --- name: analyzers -description: 'EF Core Roslyn analyzers, diagnostic analyzers, code fix providers, diagnostic suppressors. Use when working on EF1001, EF1002, InternalUsageDiagnosticAnalyzer, or StringsUsageInRawQueriesDiagnosticAnalyzer.' +description: 'Implementation details for EF Core Roslyn analyzers. Use when changing analyzers, fix providers, or diagnostic suppressors.' user-invokable: false ---- - -# EF Core Analyzers - -Roslyn analyzers shipped in `Microsoft.EntityFrameworkCore.Analyzers` (`src/EFCore.Analyzers/`). - -## When to Use - -- Adding a new diagnostic rule or code fix -- Modifying detection logic for internal API usage or SQL injection warnings -- Working on a diagnostic suppressor - -## Analyzers - -See AnalyzerReleases.Shipped.md for a complete list of shipped diagnostics. - -## Validation - -- Analyzer triggers on expected code patterns in an efficient manner -- No false positives on public API usage -- Code fix produces compilable output +--- \ No newline at end of file diff --git a/.agents/skills/bulk-operations/SKILL.md b/.agents/skills/bulk-operations/SKILL.md index d53a517a701..32b2a97b891 100644 --- a/.agents/skills/bulk-operations/SKILL.md +++ b/.agents/skills/bulk-operations/SKILL.md @@ -1,31 +1,5 @@ --- name: bulk-operations -description: 'EF Core ExecuteUpdate, ExecuteDelete, set-based bulk CUD operations. Use when working on bulk update/delete LINQ translation or UpdateExpression/DeleteExpression SQL AST nodes.' +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 --- - -# Bulk Operations - -`ExecuteUpdate`/`ExecuteDelete` translate LINQ to set-based SQL UPDATE/DELETE, bypassing change tracking. Return affected row count. - -## When to Use - -- Adding or fixing translation of `ExecuteUpdate`/`ExecuteDelete` -- Working on `UpdateExpression`/`DeleteExpression` SQL AST nodes -- Handling provider-specific UPDATE/DELETE syntax differences - -## Key Files - -- Translation: `RelationalQueryableMethodTranslatingExpressionVisitor.ExecuteUpdate.cs` / `.ExecuteDelete.cs` -- SQL AST: `UpdateExpression.cs`, `DeleteExpression.cs` in `src/EFCore.Relational/Query/SqlExpressions/` -- Public API: `EntityFrameworkQueryableExtensions` — `ExecuteDelete`, `ExecuteUpdate` + async -- Setters: `SetPropertyCalls.cs`, `UpdateSettersBuilder.cs` - -## Testing - -Specification tests: `test/EFCore.Specification.Tests/BulkUpdates/`. Provider overrides in `test/EFCore.{Provider}.FunctionalTests/BulkUpdates/`. - -## Validation - -- New operations translate to correct SQL -- Unsupported scenarios throw at translation time, not at runtime diff --git a/.agents/skills/change-tracking/SKILL.md b/.agents/skills/change-tracking/SKILL.md index 829f6f7a245..71a6f98659a 100644 --- a/.agents/skills/change-tracking/SKILL.md +++ b/.agents/skills/change-tracking/SKILL.md @@ -1,6 +1,6 @@ --- name: change-tracking -description: 'EF Core change tracking, entity states, StateManager, snapshot comparison, change detection, complex properties/collections, property values, property accessors, proxies. Use when working on InternalEntityEntry, ChangeDetector, or SnapshotFactoryFactory.' +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 --- @@ -8,30 +8,13 @@ user-invokable: false Manages entity states and detects changes for `SaveChanges()`. -## When to Use - -- Modifying how entity state transitions work -- Working on snapshot comparison or change detection -- Debugging property accessor expression trees or ordinal indexing -- Working on change tracking or lazy loading proxies - ## Core Components - `StateManager` — central engine, identity maps, tracks all entities - `InternalEntityEntry` — per-entity state, property flags, snapshots -- `ChangeDetector` — calls `DetectChanges()` which compares snapshots -- `ChangeTracker` — public API wrapping StateManager - -## Snapshots - -Built by `SnapshotFactoryFactory` subclasses via compiled expression trees. - -## Property Accessors - -Compiled expression trees in `PropertyAccessorsFactory`: -- Ordinals in `indices` parameter specify element at each complex collection depth - -Getters and setterscompiled lazily via `ClrPropertyGetterFactory` ands `ClrPropertySetterFactory`. +- `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 @@ -41,7 +24,7 @@ Unit tests: `test/EFCore.Tests/ChangeTracking/`. Functional tests: `test/EFCore. | Pitfall | Solution | |---------|----------| -| `SharedIdentityEntry` for deleted entities (table splitting) | These are skipped by `DetectChanges` to avoid double-processing | +| There is a failure when there is shared identity entry (Added and Deleted) | Add code that checks `SharedIdentityEntry` | ## Validation diff --git a/.agents/skills/cosmos-provider/SKILL.md b/.agents/skills/cosmos-provider/SKILL.md index 448784b5791..1b7458dc2de 100644 --- a/.agents/skills/cosmos-provider/SKILL.md +++ b/.agents/skills/cosmos-provider/SKILL.md @@ -1,6 +1,6 @@ --- name: cosmos-provider -description: 'EF Core Azure Cosmos DB provider, Cosmos query translation, Cosmos SQL generation, document storage, partition keys. Use when working on CosmosQueryableMethodTranslatingExpressionVisitor, CosmosClientWrapper, or Cosmos-specific features.' +description: 'Implementation details for the EF Core Azure Cosmos DB provider. Use when changing Cosmos-specific code.' user-invokable: false --- @@ -20,17 +20,3 @@ Non-relational provider with its own parallel query pipeline. Uses JSON for docu - Partition key configuration required for performance - `ETag` for optimistic concurrency - No cross-container joins - -## Other Key Files - -| Area | Path | -|------|------| -| LINQ → Cosmos | `src/EFCore.Cosmos/Query/Internal/CosmosQueryableMethodTranslatingExpressionVisitor.cs` | -| Expression → Cosmos SQL | `src/EFCore.Cosmos/Query/Internal/CosmosSqlTranslatingExpressionVisitor.cs` | -| SQL generation | `src/EFCore.Cosmos/Query/Internal/CosmosQuerySqlGenerator.cs` | -| Compilation | `src/EFCore.Cosmos/Query/Internal/CosmosShapedQueryCompilingExpressionVisitor.cs` | -| SQL AST nodes | `src/EFCore.Cosmos/Query/Internal/Expressions/` | - -## Validation - -- Provider functional tests pass against a Cosmos emulator or live instance 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/<name>.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/ +└── <agent-name>.md # Agent definition +``` + +Template: + +```markdown +--- +name: my-agent +description: A short description of what this agent does and when to use it. +--- + +# <Agent Title> + +You are an expert in <domain>. Your job is to: +- <behavior 1> +- <behavior 2> + +## Guidelines + +- <guideline 1> +- <guideline 2> + +## Workflow + +1. <step 1> +2. <step 2> + +## Constraints + +- <constraint 1> +- <constraint 2> + +``` + +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:<tool-name>` 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 <domain>.', + 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 index 38d126edecc..638d33819bf 100644 --- a/.agents/skills/dbcontext-and-services/SKILL.md +++ b/.agents/skills/dbcontext-and-services/SKILL.md @@ -1,6 +1,6 @@ --- name: dbcontext-and-services -description: 'EF Core DbContext, DbContextOptions, dependency injection, service registration, DbContext pooling, IServiceProvider management. Use when working on context configuration, service lifetimes, or the Dependencies pattern.' +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 --- @@ -8,37 +8,13 @@ user-invokable: false EF Core's internal DI container, service registration, and context lifecycle management. -## When to Use - -- Adding a new EF Core service or changing service lifetimes -- Working on DbContext pooling behavior -- Modifying how options extensions are processed -- Understanding the `Dependencies` record pattern for service injection - ## Service Registration `EntityFrameworkServicesBuilder` maintains a `CoreServices` dictionary mapping service types to `ServiceCharacteristics` (lifetime + multi-registration flag). -Pattern: Providers call `TryAddProviderSpecificServices()` first, then `TryAddCoreServices()` fills remaining services without overriding existing registrations. - ## Dependencies Pattern Services receive dependencies via sealed records (not constructor injection of individual services): ```csharp public sealed record MyServiceDependencies(IDep1 Dep1, IDep2 Dep2); ``` - -## Other Key Files - -- `src/EFCore/DbContext.cs` — main context, implements `IDbContextPoolable` -- `src/EFCore/Infrastructure/DbContextOptions.cs` — immutable sorted dictionary of `IDbContextOptionsExtension` -- `src/EFCore/Internal/DbContextServices.cs` — scoped service resolver, model creation, provider validation -- `src/EFCore/Internal/DbContextPool.cs` — manages a pool of `IDbContextPoolable` instances. Options are frozen at pool creation. - -## Testing - -Unit tests: `DbContextTest.cs`, `EntityFrameworkServiceCollectionExtensionsTest.cs`. - -## Validation - -- Service resolution uses appropriate lifetimes and doesn't throw diff --git a/.agents/skills/make-instructions/SKILL.md b/.agents/skills/make-instructions/SKILL.md index d61091bae4a..551dc3eddd6 100644 --- a/.agents/skills/make-instructions/SKILL.md +++ b/.agents/skills/make-instructions/SKILL.md @@ -7,12 +7,6 @@ description: 'Create VS Code file-based instructions (.instructions.md files). U 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 to Use - -- Creating a new `.instructions.md` file from scratch -- Adding language-specific, framework-specific, or module-specific coding guidelines -- Providing background knowledge about a subsystem that Copilot should consider when editing matching files - ## When Not to Use - Setting project-wide instructions — use `.github/copilot-instructions.md` or `AGENTS.md` instead diff --git a/.agents/skills/make-skill/SKILL.md b/.agents/skills/make-skill/SKILL.md index 8a0b8213e30..f519d981ea0 100644 --- a/.agents/skills/make-skill/SKILL.md +++ b/.agents/skills/make-skill/SKILL.md @@ -7,11 +7,6 @@ description: 'Create new Agent Skills for GitHub Copilot. Use when asked to crea 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 to Use - -- Creating a new skill from scratch -- Generating a SKILL.md file with proper frontmatter in compliance with agentskills.io specification - ## When Not to Use - Creating custom agents (use the agents/ directory pattern) @@ -70,13 +65,12 @@ allowed-tools: <Optional, list of pre-approved tools that agents could use when 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 to Use**: Bullet list of appropriate scenarios -3. **When Not to Use**: Bullet list of exclusions, optional -4. **Inputs and Outputs**: Example inputs and expected outputs, if applicable -5. **Workflow**: Numbered steps with checkpoints -6. **Testing**: Instructions for how to create automated tests for the skill output, if applicable -7. **Validation**: How to confirm the skill worked correctly -8. **Common Pitfalls**: Known traps and how to avoid them +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 diff --git a/.agents/skills/migrations/SKILL.md b/.agents/skills/migrations/SKILL.md index 1490719cca5..a8e901937e2 100644 --- a/.agents/skills/migrations/SKILL.md +++ b/.agents/skills/migrations/SKILL.md @@ -1,6 +1,6 @@ --- name: migrations -description: 'EF Core migrations, migration scaffolding, MigrationsSqlGenerator, model diffing, migration operations, HistoryRepository, Migrator. Use when working on migrations add, database update, or migration SQL generation.' +description: 'Implementation details for EF Core migrations. Use when changing MigrationsSqlGenerator, model diffing, migration operations, HistoryRepository, the Migrator or related classes.' user-invokable: false --- @@ -12,20 +12,6 @@ user-invokable: false **Apply migration**: `Migrator.MigrateAsync()` → reads `__EFMigrationsHistory` → per pending: `MigrationsSqlGenerator.Generate(operations)` → `MigrationCommandExecutor` executes -## Other Key Files - -| Area | Path | -|------|------| -| Operation generator | `src/EFCore.Design/Migrations/Design/CSharpMigrationOperationGenerator.cs` | -| History | `src/EFCore.Relational/Migrations/HistoryRepository.cs` | -| Operations | `src/EFCore.Relational/Migrations/Operations/` | - -Provider overrides: `SqlServerMigrationsSqlGenerator`, `SqliteMigrationsSqlGenerator` - ## 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`. - -## Validation - -- Generated migration code compiles and produces correct SQL +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 index 6d044b2a53f..9a9952c1756 100644 --- a/.agents/skills/model-building/SKILL.md +++ b/.agents/skills/model-building/SKILL.md @@ -1,6 +1,6 @@ --- name: model-building -description: 'EF Core model building, conventions, metadata interfaces, model initialization, runtime annotations, RuntimeModelConvention. Use when working on ConventionSet, ModelBuilder, IConvention implementations, ModelRuntimeInitializer, or RuntimeModel.' +description: 'Implementation details for EF Core model building. Use when changing ConventionSet, ModelBuilder, IConvention implementations, ModelRuntimeInitializer, RuntimeModel, or related classes.' user-invokable: false --- @@ -8,14 +8,6 @@ user-invokable: false Covers model construction (conventions, fluent API, metadata hierarchy) and model initialization (runtime annotation propagation, compiled model filtering). -## When to Use - -- Adding or modifying a convention -- Changing the fluent API or metadata builders -- Adding a new model-level annotation -- Working on `ModelRuntimeInitializer`, `RuntimeModelConvention`, or compiled model annotation filtering -- Understanding the `IReadOnly*` → `IMutable*` → `IConvention*` → `IRuntime*` interface hierarchy - ## Convention System `ConventionSet` (`src/EFCore/Metadata/Conventions/ConventionSet.cs`) holds `List<I*Convention>` for every metadata event. Key conventions in `src/EFCore/Metadata/Conventions/`: @@ -68,12 +60,6 @@ Created lazily by `RelationalModelRuntimeInitializer`, accessed via `model.GetRe `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. -## Other Key Files - -- `src/EFCore/ModelBuilder.cs` — fluent API entry point -- `src/EFCore/Metadata/Internal/Model.cs` — mutable model -- `src/EFCore/Metadata/RuntimeModel.cs` — runtime model - ## Testing | Area | Location | diff --git a/.agents/skills/query-pipeline/SKILL.md b/.agents/skills/query-pipeline/SKILL.md index 1758e319d28..246800506a3 100644 --- a/.agents/skills/query-pipeline/SKILL.md +++ b/.agents/skills/query-pipeline/SKILL.md @@ -1,6 +1,6 @@ --- name: query-pipeline -description: 'EF Core LINQ query translation, compilation, SQL generation, shaper, materialization. Use when working on query translation, expression visitors, SqlExpressions, QuerySqlGenerator, or ShaperProcessingExpressionVisitor.' +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 --- @@ -8,48 +8,13 @@ user-invokable: false Translates LINQ expressions into database queries and materializes results. -## When to Use - -- Adding or modifying query translation for a LINQ operator -- Adding a new SQL expression type or method/member translator -- Debugging incorrect SQL generation or materialization -- Working on the shaper, JSON column handling, or split queries - ## Stages 1. **Preprocessing** — `QueryTranslationPreprocessor`: `NavigationExpandingExpressionVisitor` (Include, navigations, auto-includes), `QueryOptimizingExpressionVisitor` -2. **Translation** — `QueryableMethodTranslatingExpressionVisitor`: LINQ methods → `ShapedQueryExpression` (= `QueryExpression` + `ShaperExpression`). Relational: QueryExpression = `SelectExpression` -3. **Postprocessing** — `QueryTranslationPostprocessor`: `SqlNullabilityProcessor`, `SqlTreePruner`, `SqlAliasManager`, `RelationalParameterBasedSqlProcessor` -4. **Compilation** — `ShapedQueryCompilingExpressionVisitor` → executable delegate. Relational: `ShaperProcessingExpressionVisitor` builds materialization code - -Entry point: `QueryCompiler.CompileQueryCore()` → `QueryCompilationContext`. Result cached in `CompiledQueryCache`. - -## Key Files - -| Area | Path | -|------|------| -| Compilation context | `src/EFCore/Query/QueryCompilationContext.cs` | -| Navigation expansion | `src/EFCore/Query/Internal/NavigationExpandingExpressionVisitor.cs` | -| LINQ → SQL | `src/EFCore.Relational/Query/RelationalQueryableMethodTranslatingExpressionVisitor.cs` | -| C# → SQL expressions | `src/EFCore.Relational/Query/RelationalSqlTranslatingExpressionVisitor.cs` | -| SQL AST → string | `src/EFCore.Relational/Query/QuerySqlGenerator.cs` | -| Materialization | `src/EFCore.Relational/Query/RelationalShapedQueryCompilingExpressionVisitor.ShaperProcessingExpressionVisitor.cs` | -| SQL expression factory | `src/EFCore.Relational/Query/SqlExpressionFactory.cs` | -| SQL AST nodes | `src/EFCore.Relational/Query/SqlExpressions/` | -| ExecuteUpdate/Delete | partial files on `RelationalQueryableMethodTranslatingExpressionVisitor` | - -## Method/Member Translation - -Provider translators implement `IMethodCallTranslator` / `IMemberTranslator`, registered via the provider's `MethodCallTranslatorProvider`. Located in `src/EFCore.{Provider}/Query/Internal/Translators/`. - -Adding a new translator: -1. Implement `IMethodCallTranslator` — check `method.DeclaringType` before translating -2. Add to the provider's `*MethodCallTranslatorProvider` constructor's `AddTranslators()` call -3. Check the base relational layer first — common translations (e.g., `Math.Max`) may already exist - -## Cosmos Pipeline - -Parallel pipeline in `src/EFCore.Cosmos/Query/Internal/`: `CosmosQueryableMethodTranslatingExpressionVisitor`, `CosmosSqlTranslatingExpressionVisitor`, `CosmosQuerySqlGenerator`. Uses `JObject` materialization. Does not use any relational query infrastructure. +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 diff --git a/.agents/skills/scaffolding/SKILL.md b/.agents/skills/scaffolding/SKILL.md index c584b6f5cdb..54b3bf72da6 100644 --- a/.agents/skills/scaffolding/SKILL.md +++ b/.agents/skills/scaffolding/SKILL.md @@ -1,6 +1,6 @@ --- name: scaffolding -description: 'EF Core scaffolding (reverse engineering), CSharpModelGenerator, database schema reading, code generation. Use when working on ef dbcontext scaffold.' +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 --- @@ -8,11 +8,6 @@ user-invokable: false Generates C# code from database schemas (reverse engineering). -## When to Use - -- Modifying how `dotnet ef dbcontext scaffold` generates code -- Changing how database schemas are read by a provider's `IDatabaseModelFactory` - ## When Not to Use - Working on compiled model generation (`dotnet ef dbcontext optimize`) @@ -20,17 +15,4 @@ Generates C# code from database schemas (reverse engineering). ## Reverse Engineering Pipeline: `IDatabaseModelFactory` (reads schema) → `IScaffoldingModelFactory` (builds EF model) → `IModelCodeGenerator` (generates C#) - -Key files in `src/EFCore.Design/Scaffolding/`: - `IReverseEngineerScaffolder` — orchestrates full pipeline -- `Internal/CSharpModelGenerator.cs` — default C# generator - -Provider factories: `SqlServerDatabaseModelFactory`, `SqliteDatabaseModelFactory` - -## Design-Time Services - -`IDesignTimeServices` — provider/plugin registers design-time services. `DesignTimeServicesBuilder` discovers them. - -## Testing - -Scaffolding tests: `test/EFCore.Design.Tests/Scaffolding/`. diff --git a/.agents/skills/servicing-pr/SKILL.md b/.agents/skills/servicing-pr/SKILL.md index b1bbf10548b..958d631ef92 100644 --- a/.agents/skills/servicing-pr/SKILL.md +++ b/.agents/skills/servicing-pr/SKILL.md @@ -1,17 +1,12 @@ --- 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, or when the user mentions servicing, patch, or release branch.' +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. -## When to Use - -- Creating a PR that targets a `release/*` branch -- Backporting a fix from `main` to a servicing branch - ## Backport Target Branch - If a version is specified, target `release/XX.0` (e.g., `backport to 10` → `release/10.0`) diff --git a/.agents/skills/sqlite-adonet/SKILL.md b/.agents/skills/sqlite-adonet/SKILL.md index fd8dc15ac83..17a5e9c267a 100644 --- a/.agents/skills/sqlite-adonet/SKILL.md +++ b/.agents/skills/sqlite-adonet/SKILL.md @@ -1,6 +1,6 @@ --- name: sqlite-adonet -description: 'Microsoft.Data.Sqlite ADO.NET provider for SQLite. Use when working on SqliteConnection, SqliteCommand, SqliteDataReader, connection pooling, user-defined functions, or SQLite-specific ADO.NET functionality.' +description: 'Implementation details for the Microsoft.Data.Sqlite ADO.NET provider. Use when changing files under `src/Microsoft.Data.Sqlite.Core/`.' user-invokable: false --- @@ -8,29 +8,7 @@ user-invokable: false Standalone ADO.NET provider in `src/Microsoft.Data.Sqlite.Core/`, independent of EF Core. Implements `System.Data.Common` abstractions. -## When to Use - -- Working on SQLite connection, command, or data reader behavior -- Modifying connection pooling logic -- Adding or changing user-defined function registration -- Debugging SQLite-specific data type handling - -## Key Classes - -| Class | Purpose | -|-------|---------| -| `SqliteConnection` | Connection lifecycle, `CreateFunction`/`CreateAggregate` | -| `SqliteCommand` | SQL execution, prepared statements | -| `SqliteDataReader` | Result set reading | -| `SqliteConnectionPool` | Warm/cold pool stacks, prune timer (2-4 min interval) | -| `SqliteConnectionPoolGroup` | Groups pools by connection string | -| `SqliteBlob` | Streaming blob I/O via `sqlite3_blob_*` APIs | - ## Notable Implementation Details - Static constructor calls `SQLitePCL.Batteries_V2.Init()` reflectively -- Connection pooling is opt-in (`Pooling=True` in connection string) - `CreateFunction()`/`CreateAggregate()` overloads generated from T4 templates (`.tt` files) -- Core implementation: `CreateFunctionCore<TState, TResult>` wraps .NET delegates into SQLitePCL callbacks -- No true async I/O — async methods are sync wrappers -- File-based or `Data Source=:memory:` for in-memory databases diff --git a/.agents/skills/testing/SKILL.md b/.agents/skills/testing/SKILL.md index da81d002a4e..99fdc86f556 100644 --- a/.agents/skills/testing/SKILL.md +++ b/.agents/skills/testing/SKILL.md @@ -1,6 +1,6 @@ --- name: testing -description: 'EF Core test infrastructure, debugging failing tests, writing new tests, SQL baseline assertions, fixtures, test helpers. Use when adding tests, debugging test failures, fixing SQL baselines, or understanding the test class hierarchy.' +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 --- @@ -8,12 +8,6 @@ user-invokable: false EF Core test infrastructure, patterns, and workflows for unit, specification, and functional tests. -## When to Use - -- Adding new unit or functional tests -- Debugging test failures (model validation, SQL or compiled model baseline mismatch) -- Understanding which test project and base class to use - ## Test Categories ### Unit Tests (`test/EFCore.{Provider}.Tests/`) diff --git a/.agents/skills/tooling/SKILL.md b/.agents/skills/tooling/SKILL.md index 1e4f70a2cf2..b6d6217d858 100644 --- a/.agents/skills/tooling/SKILL.md +++ b/.agents/skills/tooling/SKILL.md @@ -1,6 +1,6 @@ --- name: tooling -description: 'EF Core dotnet-ef CLI tool, Package Manager Console commands, EFCore.Tools PowerShell module, EFCore.Tasks MSBuild integration. Use when working on dotnet-ef commands, the ef wrapper, or tool infrastructure.' +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 --- @@ -8,12 +8,6 @@ user-invokable: false The `dotnet ef` CLI and Visual Studio Package Manager Console commands for migrations, scaffolding, and compiled models. -## When to Use - -- Adding or modifying a `dotnet ef` command -- Working on PMC (PowerShell) command wrappers -- Debugging tool invocation, project discovery, or MSBuild integration - ## 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`. @@ -26,21 +20,6 @@ PowerShell module: `Add-Migration`, `Update-Database`, `Scaffold-DbContext`, `Op NuGet package `Microsoft.EntityFrameworkCore.Tasks` provides build/publish-time compiled model and precompiled query generation. -### Key Classes - -- `OptimizeDbContext` — public MSBuild task. Invokes `dotnet exec ef.dll dbcontext optimize`, collects generated `.g.cs` files as `[Output]` -- `OperationTaskBase` — abstract base extending `ToolTask`. Orchestrates `dotnet exec ef.dll` with assembly/deps/runtimeconfig args. Parses prefixed output into MSBuild errors/warnings - -### Build Properties (user-configurable in `.csproj`) - -| Property | Default | Purpose | -|----------|---------|--------| -| `EFOptimizeContext` | unset | `true` enables generation outside NativeAOT publish | -| `EFScaffoldModelStage` | `publish` | `publish` or `build` — when to generate compiled model | -| `EFPrecompileQueriesStage` | `publish` | `publish` or `build` — when to precompile queries | -| `DbContextType` | `*` | Specific `DbContext` to optimize, `*` = all | -| `EFOutputDir` | `$(IntermediateOutputPath)` | Directory for generated files | - ### Build Integration Flow Targets in `buildTransitive/Microsoft.EntityFrameworkCore.Tasks.targets`: diff --git a/.agents/skills/update-pipeline/SKILL.md b/.agents/skills/update-pipeline/SKILL.md index ceb8d19c96d..b27636eaf4d 100644 --- a/.agents/skills/update-pipeline/SKILL.md +++ b/.agents/skills/update-pipeline/SKILL.md @@ -1,6 +1,6 @@ --- name: update-pipeline -description: 'EF Core SaveChanges, modification commands, command batching, update SQL generation, stored procedure updates. Use when working on the update pipeline, CommandBatchPreparer, UpdateSqlGenerator, or ModificationCommand.' +description: 'Implementation details for EF Core SaveChanges and the update pipeline. Use when changing CommandBatchPreparer, UpdateSqlGenerator, ModificationCommand, or related classes.' user-invokable: false --- @@ -8,13 +8,6 @@ user-invokable: false Converts tracked entity changes into database INSERT/UPDATE/DELETE commands during `SaveChanges()`. -## When to Use - -- Modifying how changes are batched or ordered -- Working on SQL generation for INSERT/UPDATE/DELETE -- Handling store-generated values (identity, computed columns) -- Debugging concurrency or transaction issues in SaveChanges - ## Flow `SaveChanges()` → ``DetectChanges()` → `IDatabase.SaveChanges()` @@ -27,11 +20,8 @@ Converts tracked entity changes into database INSERT/UPDATE/DELETE commands duri → `BatchExecutor` executes all batches in a transaction → `StateManager.AcceptAllChanges()` -## Other Key Files - -| Area | Path | -|------|------| -| Shared tables | `src/EFCore.Relational/Update/Internal/SharedTableEntryMap.cs` | +Other Key Files: +- `src/EFCore.Relational/Update/Internal/SharedTableEntryMap.cs` — manages entries mapped to the same row ## Concurrency From 46afaac79bf426c03aed646e2ae0d989f6f8757d Mon Sep 17 00:00:00 2001 From: Andriy Svyryd <AndriySvyryd@users.noreply.github.com> Date: Wed, 25 Feb 2026 16:10:26 -0800 Subject: [PATCH 13/14] Update .agents/skills/update-pipeline/SKILL.md Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .agents/skills/update-pipeline/SKILL.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.agents/skills/update-pipeline/SKILL.md b/.agents/skills/update-pipeline/SKILL.md index b27636eaf4d..50ee6009776 100644 --- a/.agents/skills/update-pipeline/SKILL.md +++ b/.agents/skills/update-pipeline/SKILL.md @@ -10,7 +10,7 @@ Converts tracked entity changes into database INSERT/UPDATE/DELETE commands duri ## Flow -`SaveChanges()` → ``DetectChanges()` → `IDatabase.SaveChanges()` +`SaveChanges()` → `DetectChanges()` → `IDatabase.SaveChanges()` → `UpdateAdapter` creates `IUpdateEntry` list → `CommandBatchPreparer.BatchCommands()` → `ModificationCommand` per entity (maps to table row), composed of `ColumnModification` (maps to column value) From 9539a775881bce00e53ca755c4fad1c025e7ed9c Mon Sep 17 00:00:00 2001 From: Andriy Svyryd <Andriy.Svyryd@microsoft.com> Date: Wed, 25 Feb 2026 18:33:14 -0800 Subject: [PATCH 14/14] Add a note on model snapshots --- .agents/skills/model-building/SKILL.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/.agents/skills/model-building/SKILL.md b/.agents/skills/model-building/SKILL.md index 9a9952c1756..1fbf29894b6 100644 --- a/.agents/skills/model-building/SKILL.md +++ b/.agents/skills/model-building/SKILL.md @@ -60,6 +60,15 @@ Created lazily by `RelationalModelRuntimeInitializer`, accessed via `model.GetRe `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 | @@ -76,3 +85,4 @@ Created lazily by `RelationalModelRuntimeInitializer`, accessed via `model.GetRe - 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