Repository navigation
Releases: Nulifyer/SqlLinqer
Release list
SqlLinqer 2.4.0-rc.2
SqlLinqer 2.4.0-rc.2 replaces JSON result transport with native database values for typed queries. This candidate is intended for application validation before a stable release.
Changes
- Stream complete parent models with their selected nested data. Server providers use correlated native records; SQLite uses prepared child queries on the same connection.
- Keep filtering, DISTINCT, grouping, ordering, and paging in SQL. Parent DISTINCT compares selected scalar columns and required relationship keys. It does not deduplicate child collections or compare object graphs in memory.
- Support SQLite nested DISTINCT with
PRAGMA query_only=ON, without library-created TEMP tables. - Share constructor/member mapping between native and tabular readers. Reduce temporary allocations and use shorter compilation-scoped aliases.
- Preserve cancellation, early stream termination, and caller-owned connection/transaction handling.
- Remove the core System.Text.Json dependency. The .NET Standard 2.1 asset has no package dependencies; 2.0 retains Microsoft.Bcl.AsyncInterfaces for async compatibility.
Compatibility
The supported typed query interfaces remain the compatibility target. JSON-specific APIs, low-level connector functions, and string-only rendering extensions are not preserved. Typed SELECT rendering extensions use CompileSelect and must preserve the compiled result layout.
For .Select(Name).Select(Permissions).Distinct(), different relationship IDs keep same-name users separate. Child rows retain their SQL multiplicity. With DISTINCT, order by a selected scalar column or required relationship key.
Validation limits
Live Azure SQL and Windows .NET Framework runtime testing have not been performed locally. The core continues to target .NET Standard 2.0 and 2.1. Please validate your application's models, queries, cancellation, and transactions against this prerelease before deployment.
SqlLinqer 2.4.0-rc.1
First release candidate for the next minor version after 2.3.1.
Multiple procedure result tables
Use SqlLinqerMultiCallable<TResults> for procedures without input parameters, or SqlLinqerMultiCallable<TInput, TResults> for procedures with inputs. Keep the same Execute() and ExecuteAsync() model. Declare an ordered value tuple with the collection type wanted for each result table:
[SqlProcedure("GetUsersAndTotals", Schema = "dbo")]
public sealed class GetUsersAndTotals
: SqlLinqerMultiCallable<(UserRow[] Users, IReadOnlyList<long> Totals)> { }
var response = await new GetUsersAndTotals().ExecuteAsync(connector);
var tables = response.GetResultOrThrow();Responses preserve the error-as-value contract and expose RETURN codes and affected-row counts. Missing, extra, or invalid result tables fail the complete call and clear results and metadata. Return totals explicitly as result-table data. Built-in collection types and registered custom collection factories are supported, with factories captured per invocation.
Typed table-valued inputs
Procedure inputs can declare mapped row objects or collections with an existing SQL table TypeName. The library uses the insert mapper for column selection, names, exclusions, enum storage, decimal handling, and binary values. Empty collections retain their SQL schema. DataTable inputs remain supported. Generated payloads and asynchronous snapshots have explicit ownership and disposal.
TVP reuse and expiration are enabled by default
TVP inserts share deterministic SQL contract-named types across requests and application nodes. Different rendered column contracts receive different names, allowing deployments to coexist. UseTvpType selects an existing application-owned type without creating, adopting, or dropping it.
Managed types use database-backed leases and transaction-owned execution guards. Defaults are a five-minute lease, 24-hour retention after expiry, and cleanup checks at most hourly per connector/database/schema. Cleanup removes up to 100 eligible types per pass, removes their lease rows, checks ownership and generation again, and preserves active transactions and procedure dependencies. Catalog provisioning and cleanup coordinate across schemas to avoid competing DDL transactions.
The existing schema must permit creating types and the owned _SqlLinqerTvpLeases_v1 registry table. Executing nodes need registry read/write permissions; cleanup needs permission to drop managed types. The registry table persists for future use. All consumers must use the lease-aware execution protocol before sharing types with online cleanup.
Cleanup runs during TVP activity or explicit CleanupExpiredTvpTypes() calls. Use a scheduled cleanup caller for databases with no application traffic. There is no background timer. AutoCleanupTvpTypes = false disables a connector's automatic checks; ReuseTvpTypes = false selects per-execution types.
Packages and validation
All three packages use 2.4.0-rc.1: SqlLinqer, SqlLinqer.Diagnostics, and SqlLinqer.Extensions.DependencyInjection. The optional packages depend on the matching core version. All continue to target .NET Standard 2.0.
- All six local/database suites passed 3,902 checks, including 307 live SQL Server checks covering concurrent cold starts and schemas, independent processes, crashed and paused nodes, rollback, cancellation, renewal races, stale generations, and cleanup bounds.
- Deliberate removal of execution and retirement safeguards triggered the intended failing assertions.
- CI validation passed compatibility builds, database suites, adoption/HTTP and runner checks, formatting, stable SQL JSON contracts, and minimum SQLite validation.
- Package-only consumers passed 58 checks using locally packed RC packages and another 58 using the exact release-workflow package artifacts. Artifact metadata identifies commit
4487fb8. Actual Azure SQL and .NET Framework 4.8 runtime execution are not covered.
Stored-procedure guide · TVP lifecycle guide · Changes since 2.3.1
Publication status
The release workflow passed validation, packing, and publishing. NuGet accepted all three 2.4.0-rc.1 packages. As of 2026-10-29 02:09 UTC, the public NuGet feed has not listed them yet, and an isolated nuget.org-only restore reports NU1102. Public-feed availability verification remains pending NuGet processing. The exact workflow package artifacts passed all 58 package-only consumer checks.
SqlLinqer 2.3.1
SqlLinqer 2.3.1 fixes the missing no-input procedure contract. Define procedures as SqlLinqerCallable<TOutput> and call Execute(), ExecuteAsync(), or Render() without an empty input model.
[SqlProcedure("GetUsers", Schema = "dbo")]
public sealed class GetUsers : SqlLinqerCallable<UserRow> { }
// Inside an application method:
var response = await new GetUsers().ExecuteAsync(connector, cancellationToken: cancellationToken);The new contract supports SQL Server and Azure SQL, output row models and scalar types, retained/default/explicit connectors, caller-owned transactions, per-call command timeouts, and asynchronous cancellation. Responses retain the existing rows, return code, affected-row count, and automatically discovered standard total outputs.
SqlLinqerCallable<TInput, TOutput> remains supported, including existing empty input models. Procedure mapping and execution are shared between the two contracts. No migration is required for existing calls.
Install matching 2.3.1 versions of SqlLinqer, SqlLinqer.Diagnostics, and SqlLinqer.Extensions.DependencyInjection when using the optional packages. All three continue to target .NET Standard 2.0.
Validation
Added 13 focused regression checks, real SqlClient syntax and binding coverage, and a live SQL Server case covering no-input execution in both styles, all connector routes, standard total outputs, return codes, and caller-owned transactions. Existing procedure checks remain in place. All six database suites passed 3,695 checks with no failures, including the new no-input SQL Server execution case.
The pre-release validation workflow passed, including disposable PostgreSQL, MySQL, and SQL Server suites, compatibility builds, integration and HTTP checks, formatting, stable SQL JSON contracts, and minimum SQLite 3.38. A package-only consumer also passed 58 checks using locally packed 2.3.1 packages. Actual Azure SQL and .NET Framework 4.8 runtime execution are not covered.
Stored-procedure guide · Changes since 2.3.0
Publication status
The release workflow passed all validation, packing, and NuGet publishing jobs. NuGet accepted all three 2.3.1 packages. As of 2026-10-26 19:33 UTC, all three versions are still unavailable in the public NuGet feed. A fresh nuget.org-only restore reports NU1102 for 2.3.1, so public-package verification remains pending. All 58 consumer checks passed using locally packed 2.3.1 packages.
SqlLinqer 2.3.0
SqlLinqer 2.3.0 is the stable release of 2.3.0-rc.2. It includes matching versions of SqlLinqer, SqlLinqer.Diagnostics, and SqlLinqer.Extensions.DependencyInjection. All packages target .NET Standard 2.0. Runtime source is unchanged from RC2; the release also includes the subsequent documentation corrections and repository MIT license.
Added
- Connector-bound query factories for ordinary mapped classes, plus
EnsureSuccessandGetResultOrThrowresponse helpers. - Connection factories can configure each newly created connection. Per-query command timeouts override connector defaults.
- Independent
CountRelatedandSumRelatedprojections aggregate mapped collections without multiplying sibling rows. - Optional provider-native interruption callbacks support cancellation and execution deadlines, including running SQLite queries.
- Query tags, execution IDs, and compiler command roles correlate buffered, paged, and streaming operations.
- Optional dependency injection registrations and
ILogger/ActivitySourcediagnostics packages, published together with core. - Runtime diagnostics configuration, bounded parameter details, and independent opt-ins for SQL logs, SQL activities, values, and full exceptions.
Fixed
- Preserve nested projected ordering and remove allocations on compilation cache hits.
- Avoid SQLite write locks during read totals and omit unused grouped measures from count queries.
Migration from 2.2.0
The stored-procedure API includes breaking changes. Replace direct StoredProcedureQuery and BeginStoredProcedure usage, three-type callables, and Call with SqlLinqerCallable<TInput, TOutput> and Execute/ExecuteAsync. Map procedure names with SqlProcedure, input members with SqlParameter, and row members with SqlColumn. SqlCallableResponse<T> replaces SqlStoredProcedureResponse<T>. Custom result-set/output attributes were removed. Null ordinary inputs omit parameters to allow database defaults; use SqlArgument to send explicit SQL NULL. See the stored-procedure guide.
For applications adopting the RC diagnostics APIs, routine completions use Debug and SQL/binding details use Trace with explicit opt-ins. IncludeSql remains an alias for log SQL only; configure IncludeSqlInActivities separately. See the diagnostics guide.
Install version 2.3.0 consistently across core and any optional SqlLinqer packages.
Validation
The release workflow passed all validation, packing, and NuGet publishing jobs. Validation covered: local regression, SQLite, DuckDB, disposable PostgreSQL/MySQL/SQL Server suites, .NET 10 and .NET Framework 4.8 compatibility builds, adoption integration and HTTP checks, formatting, stable SQL JSON contracts, and minimum SQLite 3.38 checks. The disposable-database run completed 3,680 checks across six suites with no failures. Actual Azure SQL and .NET Framework 4.8 runtime execution are not covered.
Publication verification
All three stable packages are published and indexed on nuget.org: SqlLinqer 2.3.0, SqlLinqer.Diagnostics 2.3.0, and SqlLinqer.Extensions.DependencyInjection 2.3.0.
A consumer restored all three from nuget.org into a fresh package cache without project references. All 55 integration checks passed. Public package metadata identifies release commit af98b0dde526793f30dcf5e2e089e15cd769724f, includes MIT licensing and XML documentation, and declares matching core dependencies.
SqlLinqer 2.3.0-rc.2
Release candidate for query execution, relationship aggregates and operational diagnostics.
- Add independent CountRelated and SumRelated projections, preserving mapped relationship conditions without multiplying sibling collections.
- Avoid write locks in SQLite read totals and unnecessary grouped measures in count queries.
- Add an optional provider-native interruption callback for cancellation and deadlines, including running SQLite queries.
- Add execution IDs, compiler command roles, typed bounded parameter details and runtime diagnostics configuration.
- Use Debug for routine query lifecycle, Trace plus explicit opt-ins for SQL and values, and Error for failed operations. SQL logs, activities and full exceptions have separate controls.
- Include matching SqlLinqer.Diagnostics and SqlLinqer.Extensions.DependencyInjection packages in the release workflow.
Migration: routine completions move from Information to Debug; SQL and binding detail move from Debug to Trace. IncludeSql remains a log-only alias; use IncludeSqlInActivities separately. See docs/execution/diagnostics.md for configuration and migration.
Validation includes local and disposable-provider suites, Debug/Release diagnostics checks, compatibility builds, MVC workflows and a consumer restoring locally packed packages. This is a prerelease for application validation.
Publication status: SqlLinqer, SqlLinqer.Diagnostics and SqlLinqer.Extensions.DependencyInjection 2.3.0-rc.2 are published and indexed on nuget.org. Use matching package versions. All release validation, packing and publishing jobs passed.
SqlLinqer 2.3.0-rc.1
Release candidate for the additive query and diagnostics APIs.
- Connector-bound query factories support ordinary mapped classes.
- EnsureSuccess and GetResultOrThrow simplify response handling while preserving metadata.
- Tag and the core observer API expose named buffered and streaming operations.
- Reproducible SQLite comparisons and updated user guides explain practical strengths and limits.
- The publishing guide establishes MAJOR.MINOR.PATCH-rc.N for future prereleases.
This publishes the core SqlLinqer package. The optional DI and ILogger/ActivitySource projects remain available in source pending their separate publishing setup. The earlier 2.3.0-preview.1 is preserved under its original version.
SqlLinqer 2.3.0-preview.1
Preview of the adoption and comparison work at cf6e60c.
- Create queries directly from a connector using ordinary mapped classes.
- Use EnsureSuccess and GetResultOrThrow while retaining totals and generated keys.
- Name query operations with Tag and observe buffered/streamed execution through the core observer API.
- Explore validated SQLite comparisons with Dapper, SqlKata, LINQ to DB, and EF Core.
- Follow revised user documentation and the runnable minimal API example.
The release workflow publishes the core SqlLinqer package. The optional DI and ILogger/ActivitySource integration projects are included in source and are not published by this workflow.
Recorded performance results describe their retained source identities and local SQLite workloads. Native flat-read dispatch and snapshot/count optimizations remain deferred.
SqlLinqer 2.2.0
SqlLinqer 2.2.0 is a stable minor release with additional database providers, asynchronous execution, result streaming, and fixes for complex projections and result loading. The library continues to target .NET Standard 2.0.
Added
- Azure SQL, SQLite, and DuckDB integration alongside SQL Server, PostgreSQL, and MySQL.
- Asynchronous query execution and JSON result streaming, including cancellation and cleanup after early enumeration exit.
- Detached query snapshots for repeated or concurrent compilation.
- Typed SQL Server procedure contracts and expanded table-valued parameter support.
Fixed
- Multi-level BuildQuery relationship projections, repeated relationship paths, and independent projection aliases.
- Automatic grouping for Concat, CASE expressions, mixed scalar and aggregate expressions, and relationships with additional correlation predicates.
- Nested projected ordering, paging, and total counts without multiplying root rows.
- MySQL computed grouping and PostgreSQL/MySQL DISTINCT ordering with JSON projections, including binary and nested relationship values.
- JSON numbers and booleans loading into string members, including exact numeric token text and legacy boolean casing.
- Immutable and read-only collections, native row aliases, generated inserts, SQL Server TVP decimal precision, and connector schema isolation.
- Caller transaction ownership and cleanup after execution errors or cancellation.
Performance
Span-based binary decoding, UTF-8 member matching, pooled JSON buffers, and cached native mapping plans reduce intermediate allocations.
Behavior changes since 2.1.0
- SQL result loading follows SqlLinqer mappings and ignores application JSON serialization attributes and converters. Use SqlIgnore to exclude SQL members.
- Numeric conversions reject fractional-to-integer values and overflow. Offset-bearing text loads as UTC DateTime, and DateTimeOffset requires an explicit offset.
- Callers retain ownership of supplied transactions and connections, including responsibility for rollback after errors or cancellation.
- Newtonsoft.Json is no longer a transitive dependency. Applications that use it directly need their own package reference.
Validation
The release commit passed 3,108 checks across regression, SQLite, DuckDB, SQL Server, PostgreSQL/MySQL integration, and scale suites. This includes 190 live SQL Server checks with synchronous, asynchronous, and streaming coverage.
The same 27 compatibility fixtures pass against both 2.1.0 and this release. Minimum SQLite 3.38, .NET 10 and .NET Framework 4.8 compatibility builds, formatting, and runner checks also passed. .NET Framework 4.8 runtime execution and an actual Azure SQL endpoint were not exercised.
SqlLinqer v2.2.0-rc.3
SqlLinqer 2.2.0-rc.3 adds result streaming and fixes mapping, generated inserts, precision, and resource ownership issues found during release review.
Added
- Asynchronous JSON result streaming for typed queries and projections, with cancellation and cleanup after early enumeration exit.
- Shared native value conversion rules for scalar, tabular, and callable results.
Fixed
- Immutable and read-only JSON collection loading, including nested SQL-mapped elements.
- Native row loading with SQL column names or CLR projection aliases, including DateOnly and TimeOnly scalars.
- Default-only DuckDB inserts into tables with generated columns.
- Generated SQL Server TVP decimal precision and validation of batches that cannot be represented losslessly.
- Connector schema isolation and disposable-result cleanup after execution or cleanup failures.
Performance
- Span-based SQLite hex decoding and UTF-8 JSON member matching reduce intermediate allocations.
- Native row mappers cache metadata and constructor delegates while keeping scratch storage private to each reader.
- JSON document fragment buffers are pooled and cleared when returned.
- Isolated measurements on .NET 10.0.13 reduced three-member model mapping from 232 to 136 bytes per row and 4 KiB hex decoding from 151,600 to 4,120 bytes per operation. These measurements exclude database and network work.
Behavior changes
- SQL result loading uses SQL mappings and ignores application JSON serialization attributes and converters. Use SqlIgnore to exclude SQL members.
- Numeric conversions reject fractional-to-integer values and overflow. Offset-bearing text loads as UTC DateTime, and DateTimeOffset requires an explicit offset.
- Callers retain ownership of supplied transactions and connections after errors and cancellation, including responsibility for rollback.
- Newtonsoft.Json is no longer a transitive dependency. Add a direct reference if your application uses it.
The library continues to target .NET Standard 2.0. This is a prerelease intended for application integration testing.
Validation
The release candidate passed local regression suites, minimum SQLite 3.38, formatting, compatibility builds, and the full disposable-database suite for PostgreSQL, MySQL, and SQL Server. SQL Server checks include synchronous and asynchronous high-precision decimal TVP round trips. .NET Framework 4.8 was build-checked; its runtime and an actual Azure SQL service endpoint were not exercised.
SqlLinqer v2.2.0-rc.2
This prerelease adds async execution, typed SQL Server procedure contracts, and detached query snapshots to the 2.2 series.
- Execute queries asynchronously with cancellation support and preserved caller transaction ownership.
- Map SQL Server and Azure SQL procedure inputs, multiple result sets, output parameters, and return codes with typed callable definitions.
- Capture query definitions for repeated or concurrent rendering without changing the original builder.
- Avoid SQL Server generated-type TVP deadlocks. Type creation and cleanup use separate autocommit connections while inserted rows retain their write transaction.
- Correct nullable, GUID, and enum scalar conversions, SQL delimiter escaping, and SOUNDEX rendering.
- Return empty relationship collections consistently and expand C# editor documentation for defaults, limits, and ownership rules.
Validation passed all five Docker suites with 912 checks. The release workflow passed 822 local checks and published through NuGet Trusted Publishing.
A fresh consumer restored this version from nuget.org with an empty package cache, compiled, and rendered a parameterized query. The assembly reports version 2.2.0-rc.2+093525fb669753edd88f1c65d19bcbe526431937.
NuGet package · Successful publishing workflow
dotnet add package SqlLinqer --version 2.2.0-rc.2