feat!: Native-AOT compatible store, drop Dapper#29
Conversation
Route serialization through System.Text.Json JsonTypeInfo<T> (reflection only as a quarantined fallback), replace Dapper with raw ADO.NET helpers (SqliteCommandExtensions), and rewrite SchemaIntrospector/MigrationRunner to avoid dynamic and Dapper type handlers. Library builds with 0 IL2xxx/ IL3xxx warnings. Pin SQLitePCLRaw.lib.e_sqlite3 3.50.3 to clear NU1903 / CVE-2025-6965 (Microsoft.Data.Sqlite 10.0.1 otherwise pulls the vulnerable 2.1.11). RollbackToVersionAsync now validates every definition in the range up front and throws LiteDocumentStoreException instead of silently skipping a missing one, so a rollback can no longer leave the schema partially reverted. Tests and benchmarks updated to the surviving API; docs de-staled. BREAKING CHANGE: removed IDocumentStore.QueryAsync(Expression predicate) and both SelectAsync projection overloads (needed Expression.Compile / reflection, incompatible with AOT). Use QueryAsync(jsonPath, value) or raw SQL via the Connection escape hatch. Deleted the public VirtualColumnInfo record.
There was a problem hiding this comment.
Pull request overview
This PR updates LiteDocumentStore to be Native AOT / trimming compatible by removing Dapper and routing all document (de)serialization through System.Text.Json metadata (JsonTypeInfo<T>), while also pruning reflection-heavy query/projection APIs and aligning tests/benchmarks/docs with the surviving surface area.
Changes:
- Removed Dapper usage from the library and replaced it with internal ADO.NET helpers (
SqliteCommandExtensions) using explicit parameter binding + ordinal reads. - Made serialization AOT-friendly by requiring caller-provided
JsonSerializerOptions(ideally backed by a source-generatedJsonSerializerContext), with a quarantined reflection fallback. - Removed expression-based predicate querying + projection APIs, updated tests/benchmarks/examples/docs accordingly, and tightened rollback behavior to fail fast on missing migration definitions.
Reviewed changes
Copilot reviewed 46 out of 46 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| src/tests/LiteDocumentStore.UnitTests/VirtualColumnTests.cs | Removed unit tests tied to deleted virtual-column expression translation APIs. |
| src/tests/LiteDocumentStore.UnitTests/ExpressionToJsonPathTests.cs | Removed unit tests for deleted ExpressionToJsonPath. |
| src/tests/LiteDocumentStore.UnitTests/DocumentStoreTests.cs | Removed Dapper usage and updated assertions to new ADO helpers. |
| src/tests/LiteDocumentStore.IntegrationTests/WalConcurrencyIntegrationTests.cs | Removed Dapper dependency in WAL validation assertions. |
| src/tests/LiteDocumentStore.IntegrationTests/VirtualColumnIntegrationTests.cs | Updated virtual column tests to use raw SQL + rehydration (no expression predicates). |
| src/tests/LiteDocumentStore.IntegrationTests/MigrationIntegrationTests.cs | Added coverage for “version below max is skipped” and “missing rollback definition fails fast”. |
| src/tests/LiteDocumentStore.IntegrationTests/ExceptionIntegrationTests.cs | Removed Dapper usage and switched to new parameter binding style. |
| src/tests/LiteDocumentStore.IntegrationTests/DocumentStoreIntegrationTests.cs | Removed predicate/projection tests and migrated Dapper-based checks to ADO helpers. |
| src/tests/LiteDocumentStore.IntegrationTests/DatabaseSeederExamples.cs | Updated seeded-query example to use raw SQL seeks (range predicates no longer supported in API). |
| src/tests/LiteDocumentStore.Benchmarks/VirtualColumnBenchmark.cs | Benchmarks updated to use JSON-path query API instead of expression predicates. |
| src/tests/LiteDocumentStore.Benchmarks/SimplifiedComparisonBenchmark.cs | Updated benchmark calls to the JSON-path query API. |
| src/tests/LiteDocumentStore.Benchmarks/README.md | Removed projection benchmark docs aligned with deleted APIs. |
| src/tests/LiteDocumentStore.Benchmarks/ProjectionQueryBenchmark.cs | Removed projection benchmarks tied to deleted SelectAsync APIs. |
| src/tests/LiteDocumentStore.Benchmarks/LiteDocumentStore.Benchmarks.csproj | Pinned native SQLite bundle for NU1903/CVE mitigation. |
| src/tests/LiteDocumentStore.Benchmarks/ComparisonBenchmark.cs | Updated benchmark calls to the JSON-path query API. |
| src/LiteDocumentStore/TypeHandlers/DateTimeOffsetHandler.cs | Removed Dapper type handler (no longer needed). |
| src/LiteDocumentStore/Serialization/JsonHelper.cs | Switched serialization to JsonTypeInfo<T>-based overloads with reflection fallback quarantined/suppressed. |
| src/LiteDocumentStore/Migrations/SchemaIntrospector.cs | Rewrote schema introspection to avoid dynamic and use ordinal reads. |
| src/LiteDocumentStore/Migrations/MigrationRunner.cs | Removed Dapper usage and persisted applied_at as ISO-8601 round-trip strings; added strict rollback validation. |
| src/LiteDocumentStore/LiteDocumentStore.csproj | Removed Dapper dependency, enabled <IsAotCompatible>true</IsAotCompatible>, pinned native SQLite bundle. |
| src/LiteDocumentStore/Factories/DocumentStoreFactory.cs | Plumbed serializer options into DocumentStore construction. |
| src/LiteDocumentStore/Factories/DefaultConnectionFactory.cs | Removed now-redundant SqliteConnectionExtensions helpers. |
| src/LiteDocumentStore/Core/VirtualColumnCache.cs | Removed cache tied to deleted predicate translation path. |
| src/LiteDocumentStore/Core/SqliteCommandExtensions.cs | Added internal ADO.NET helpers replacing Dapper for common operations. |
| src/LiteDocumentStore/Core/IDocumentStore.cs | Removed expression-predicate query and projection APIs (breaking change). |
| src/LiteDocumentStore/Core/ExpressionToJsonPath.cs | Removed reflection-heavy expression translation code. |
| src/LiteDocumentStore/Core/DocumentStoreOptionsBuilder.cs | Added builder support for configuring serializer options. |
| src/LiteDocumentStore/Core/DocumentStoreOptions.cs | Added SerializerOptions and cloned options support. |
| src/LiteDocumentStore/Core/DocumentStore.cs | Replaced Dapper calls with ADO helpers; routed (de)serialization through caller options; removed predicate/projection methods. |
| README.md | Updated docs for AOT/trim, raw ADO usage, and revised API surface. |
| PERFORMANCE_INVESTIGATIONS.md | Removed stale performance investigation doc. |
| IMPLEMENTATION_CHECKLIST.md | Removed stale implementation checklist doc. |
| examples/VirtualColumn.cs | Updated example to use JSON-path API and raw SQL for index seeks; still includes Dapper as a script dependency. |
| examples/README.md | Updated examples list and added AOT verification example. |
| examples/ProjectionQuery.cs | Removed example tied to deleted projection API. |
| examples/AotVerification.cs | Added AOT smoke-test example using a source-generated STJ context. |
| CLAUDE.md | Added repository guidance (architecture, build/test commands, AOT notes). |
| benchmarks/2026-01-11/LiteDocumentStore.Benchmarks.VirtualColumnBenchmark-report-github.md | Removed stale benchmark report artifact. |
| benchmarks/2026-01-11/LiteDocumentStore.Benchmarks.SimplifiedComparisonBenchmark-report-github.md | Removed stale benchmark report artifact. |
| benchmarks/2026-01-11/LiteDocumentStore.Benchmarks.ProjectionQueryBenchmark-report-github.md | Removed stale benchmark report artifact. |
| benchmarks/2026-01-11/LiteDocumentStore.Benchmarks.ComparisonBenchmark-report-github.md | Removed stale benchmark report artifact. |
| AOT_COMPATIBILITY_PLAN.md | Removed obsolete planning doc (work now implemented). |
| .github/instructions/testing.instructions.md | Removed stale Copilot instructions doc. |
| .github/instructions/patterns.instructions.md | Removed stale Copilot instructions doc. |
| .github/instructions/general.instructions.md | Updated GitHub instructions to reflect new AOT/Dapper-less architecture. |
| .github/instructions/code-style.instructions.md | Updated parameterization guidance to use new ADO helper extensions. |
| var connection = _connectionFactory.CreateConnection(options); | ||
|
|
||
| return new DocumentStore(connection, namingConvention, logger, ownsConnection: true); | ||
| return new DocumentStore(connection, namingConvention, logger, ownsConnection: true, options.SerializerOptions); |
| var connection = await _connectionFactory.CreateConnectionAsync(options).ConfigureAwait(false); | ||
|
|
||
| return new DocumentStore(connection, namingConvention, logger, ownsConnection: true); | ||
| return new DocumentStore(connection, namingConvention, logger, ownsConnection: true, options.SerializerOptions); |
| TableNamingConvention = TableNamingConvention, | ||
| AdditionalPragmas = [.. AdditionalPragmas] | ||
| AdditionalPragmas = [.. AdditionalPragmas], | ||
| SerializerOptions = SerializerOptions | ||
| }; |
| // Use table_xinfo instead of table_info to include generated columns | ||
| var sql = $"PRAGMA table_xinfo([{tableName}])"; | ||
| var pragmaResults = await _connection.QueryAsync(sql).ConfigureAwait(false); | ||
|
|
- Microsoft.* framework packages 10.0.1 -> 10.0.9 - Microsoft.NET.Test.Sdk 18.0.1 -> 18.7.0 - coverlet.collector 6.0.4 -> 10.0.1 - Microsoft.SourceLink.GitHub 8.0.0 -> 10.0.300 - Dapper (benchmarks) 2.1.66 -> 2.1.79 SQLitePCLRaw.lib.e_sqlite3 stays pinned at 3.50.3 (still overrides the vulnerable 2.1.11 that Microsoft.Data.Sqlite 10.0.9 pulls transitively). xunit kept on the 2.9.3 line; xunit.runner.visualstudio on stable 3.1.5.
GetColumnsAsync interpolated the (public-API) table name into PRAGMA table_xinfo([...]). SQLite's [ ] quoting has no escape for a literal ']', so a name containing one broke out of the identifier. Use double-quote identifier quoting with "" escaping instead. Also document that DocumentStoreOptions.Clone shares SerializerOptions by reference intentionally (source-gen resolver + cache; STJ freezes options after first use).
|
Reviewed the Copilot comments — dispositions:
All green after the fix: library 0 IL/0 NU1903, unit 30/30, integration 104/104. |
Summary
Makes
LiteDocumentStoreNative-AOT / trim compatible and removes the Dapper dependency.System.Text.JsonJsonTypeInfo<T>(viaDocumentStoreOptions.SerializerOptions); reflection kept only as a quarantined, attribute-suppressed fallback.Core/SqliteCommandExtensions.cs(explicit parameter binding, ordinal reads).SchemaIntrospectorrewritten withoutdynamic;MigrationRunnerrewritten without Dapper type handlers (applied_atpersisted as ISO-8601 round-trip string).IL2xxx/IL3xxxwarnings;<IsAotCompatible>true</IsAotCompatible>.Security
Pins
SQLitePCLRaw.lib.e_sqlite33.50.3 (native binary, no managed deps) to clear NU1903 / CVE-2025-6965 —Microsoft.Data.Sqlite 10.0.1otherwise pulls the vulnerable2.1.11.Migration robustness
RollbackToVersionAsyncnow validates every migration definition in the rollback range up front and throwsLiteDocumentStoreExceptionif any is missing, instead of silently skipping — a rollback can no longer leave the schema partially reverted.Breaking changes
IDocumentStore.QueryAsync(Expression<Func<T,bool>> predicate)and bothSelectAsyncprojection overloads (requiredExpression.Compile/ reflection). UseQueryAsync(jsonPath, value)or raw SQL via theConnectionescape hatch.VirtualColumnInforecord.Housekeeping
README.md,.github/instructions/*, old plan docs, stale benchmark reports); addedCLAUDE.md.Verification
dotnet build -c Release→ 0 warnings, no NU1903.