|
| 1 | +# AGENTS.md |
| 2 | + |
| 3 | +This file provides guidance to Codex (Codex.ai/code) when working with code in this repository. |
| 4 | + |
| 5 | +## What This Is |
| 6 | + |
| 7 | +EntityFrameworkCore.Jet is an EF Core provider for Microsoft Jet/ACE databases (Microsoft Access `.mdb`/`.accdb` files). It runs **Windows only** and bridges EF Core to the Access database engine via either ODBC or OLE DB. |
| 8 | + |
| 9 | +Current version: `10.0.x` targeting EF Core 10 and `net10.0`. |
| 10 | + |
| 11 | +## Build |
| 12 | + |
| 13 | +```powershell |
| 14 | +dotnet build EFCore.Jet.sln |
| 15 | +``` |
| 16 | + |
| 17 | +Assemblies are **strong-name signed** using `Key.snk`. `TreatWarningsAsErrors=True` is set globally — fix all warnings. |
| 18 | + |
| 19 | +### Local EFCore Repository (optional) |
| 20 | + |
| 21 | +To develop against a local EF Core build instead of NuGet packages, copy `Development.props.sample` to `Development.props` and set `LocalEFCoreRepository` to your EF Core checkout. That local build must be compiled with `AssemblyVersion=10.0.0.0` to avoid binding conflicts. |
| 22 | + |
| 23 | +## Tests |
| 24 | + |
| 25 | +Tests require a real Microsoft Access driver installed (ODBC or OLE DB) and an actual `.accdb` file — no mocks. The connection string is configured via: |
| 26 | +- `test/EFCore.Jet.FunctionalTests/config.json` (OLE DB example present) |
| 27 | +- `test/EFCore.Jet.Tests/config.json` (bare filename; picks up default provider) |
| 28 | +- Or env var `EFCoreJet_DefaultConnection` |
| 29 | + |
| 30 | +**Run all tests** (requires x86 or x64 matching your driver bitness): |
| 31 | + |
| 32 | +```powershell |
| 33 | +dotnet test EFCore.Jet.sln --configuration Debug |
| 34 | +``` |
| 35 | + |
| 36 | +**Run a single test class:** |
| 37 | + |
| 38 | +```powershell |
| 39 | +dotnet test test\EFCore.Jet.FunctionalTests\EFCore.Jet.FunctionalTests.csproj --filter "FullyQualifiedName~NorthwindQueryJetTest" |
| 40 | +``` |
| 41 | + |
| 42 | +**Run a single test method:** |
| 43 | + |
| 44 | +```powershell |
| 45 | +dotnet test test\EFCore.Jet.FunctionalTests\EFCore.Jet.FunctionalTests.csproj --filter "FullyQualifiedName=EntityFrameworkCore.Jet.FunctionalTests.Query.NorthwindQueryJetTest.Where_simple" |
| 46 | +``` |
| 47 | + |
| 48 | +Tests run in **fixed order by default** (`FIXED_TEST_ORDER` compile constant). All tests lock culture to `en-US` via a module initializer. |
| 49 | + |
| 50 | +Tests that require features Jet doesn't support are marked `[Fact(Skip = "Unsupported by JET: ...")]` — see `SkipMessages.txt` for the catalog of known unsupported patterns. |
| 51 | + |
| 52 | +## Project Structure |
| 53 | + |
| 54 | +``` |
| 55 | +src/ |
| 56 | + EFCore.Jet.Data/ ADO.NET driver — JetConnection, JetCommand, JetDataReader, |
| 57 | + schema management, DUAL table simulation, connection pooling |
| 58 | + EFCore.Jet/ EF Core provider — query pipeline, migrations, scaffolding, |
| 59 | + type mappings, value generation, conventions |
| 60 | + EFCore.Jet.Odbc/ Provider factory for ODBC data access |
| 61 | + EFCore.Jet.OleDb/ Provider factory for OLE DB data access |
| 62 | + Shared/ Shared source files compiled into multiple src projects |
| 63 | +
|
| 64 | +test/ |
| 65 | + EFCore.Jet.Data.Tests/ Unit tests for the ADO.NET driver layer |
| 66 | + EFCore.Jet.FunctionalTests/ EF Core specification tests (adapted from EF Core's own suite) |
| 67 | + EFCore.Jet.Tests/ Additional functional tests |
| 68 | + EFCore.Jet.IntegrationTests/ Integration scenario tests |
| 69 | + JetProviderExceptionTests/ Exception-path tests |
| 70 | + Shared/ Shared test infrastructure (xunit framework customizations, |
| 71 | + test orderers, conditional test attributes) |
| 72 | +``` |
| 73 | + |
| 74 | +## Architecture: Two-Layer Design |
| 75 | + |
| 76 | +**Layer 1 — `EFCore.Jet.Data`** wraps the raw ODBC/OLE DB driver: |
| 77 | +- `JetConnection` detects whether the connection string is ODBC or OLE DB and delegates to the appropriate inner `DbConnection`. |
| 78 | +- `JetCommand` rewrites SQL at runtime: handles `SELECT SKIP`, emulates `@@ROWCOUNT`, rewrites `TOP @param`, parses `IF NOT EXISTS ... THEN ...` syntax, and intercepts stored-procedure creation. |
| 79 | +- `JetConfiguration` holds global settings: `TimeSpanOffset` (Jet has no TimeSpan; dates are offset from 1899-12-30), `CustomDualTableName`, `IntegerNullValue`, `UseConnectionPooling`. |
| 80 | +- Schema operations (create/drop database, list tables) have three implementations: ADOX, DAO, and Precise, selected based on available COM libraries. |
| 81 | + |
| 82 | +**Layer 2 — `EFCore.Jet`** is the EF Core provider: |
| 83 | +- `JetServiceCollectionExtensions.AddEntityFrameworkJet()` registers all provider services. |
| 84 | +- `JetQuerySqlGenerator` extends `QuerySqlGenerator` to produce Jet-compatible SQL — converts `CAST` to Jet VBA functions (`CBOOL`, `CINT`, `CLNG`, etc.), handles boolean/numeric null semantics. |
| 85 | +- `JetQueryTranslationPostprocessor` applies Jet-specific query rewrites in order: skip/take transformation → base postprocessing → optional millisecond support → ORDER BY lifting. `JetSkipTakePostprocessor` emulates `SKIP`/`OFFSET` since Jet only supports `SELECT TOP n`. |
| 86 | +- `JetMigrationsSqlGenerator` generates DDL for Access (no `ALTER COLUMN`, limited constraint support). |
| 87 | +- `JetHistoryRepository` implements migration locking via a `__EFMigrationsLock` table with `LockReleaseBehavior.Explicit`. |
| 88 | +- `JetRelationalConnection` creates an "empty" (masterless) connection for database creation/drop operations. |
| 89 | + |
| 90 | +## Key Jet SQL Constraints |
| 91 | + |
| 92 | +These shape much of the query pipeline complexity: |
| 93 | +- No `OFFSET` — emulated via subquery or `TOP`+skip in the data layer |
| 94 | +- `SELECT TOP n` only supports a literal integer, not a parameter (rewritten at command level) |
| 95 | +- Subqueries in `SELECT` list are limited; scalar subqueries only work in `FROM` |
| 96 | +- No parallel transactions (OLE DB) |
| 97 | +- No millisecond precision in `DateTime` |
| 98 | +- `CROSS JOIN` and mixed `JOIN`/comma syntax must be ordered correctly |
| 99 | +- Booleans stored as `-1`/`0` (numeric), not `TRUE`/`FALSE` |
| 100 | +- `GUID` support is indirect |
| 101 | +- No `rowversion`, no `DateTimeOffset`, no nullable `BIT` |
| 102 | + |
| 103 | +## Versioning |
| 104 | + |
| 105 | +`Version.props` owns `VersionPrefix` and `PreReleaseVersionLabel`. Bump `VersionPrefix` after each release. Valid labels: `alpha`, `beta`, `silver`, `preview`, `rc`, `rtm`, `servicing`. CI sets `OfficialVersion`, `ContinuousIntegrationTimestamp`, and `BuildSha` automatically. |
0 commit comments