-
Notifications
You must be signed in to change notification settings - Fork 478
Releases and Roadmap
- Release 6.4.0
- Release 6.3.0
- Release 6.2.1
- Release 6.2.0
- Release 6.1.0
- Release 6.0.0
- Release 5.4.1.9
- Release 5.4.1
- Release 5.4.0
- Release 5.3.2
- Release 5.3.1
- Release 5.3.0
- Release 5.2.2
- Release 5.2.1
- Release 5.2.0
- Release 5.1.1
- Release 5.1.0
- Release 5.0.0
- Release 5.0.0 RC 2
- Release 5.0.0 RC 1
- Release 5.0.0 Preview 2
- Release 5.0.0 Preview 1
- Release 4.4.1
- Release 4.4.0
- Release 4.3.0
- Release 4.2.0
- Release 4.1.1
- Release 4.1.0
- Release 4.0.1
- Release 4.0.0
- Release 4.0.0 Release Candidate 2
- Release 4.0.0 Release Candidate 1
- Release 4.0.0 Previews 2-10
- Release 4.0.0 Preview 1
- Releases 3.x
- Older Versions
- Two new eager-loading execution strategies for
LoadWith/ThenLoadand inline child sub-query projections, alongside the existing default. KeyedQuery buffers the main query, extracts the parent keys client-side, and loads each child collection withWHERE key IN (…)— transferring far fewer columns for wide parent entities. CteUnion combines multiple same-level child collections into a singleUNION ALLCTE, collapsing several pre-queries into one round-trip when a level has two or more collections. Choose per query withWithKeyedLoadStrategy(),WithUnionLoadStrategy(), orWithSeparateLoadStrategy()(the explicit default), or set a global default withDataOptions.UseDefaultEagerLoadingStrategy(EagerLoadingStrategy.KeyedQuery). Strategies fall back automatically (CteUnion → KeyedQuery → Default) when a query can't be expressed by the chosen one. A companionDataOptions.UseImplicitCollectionLoading(ImplicitCollectionLoading.Throw)makes a collection projected in aselectwithout an explicitLoadWith/ThenLoador strategy marker fail at build time (defaultAllowkeeps current behavior). See details below. (#5450) - New
Sql.Window.*fluent API for window functions, replacing the olderSql.Ext.*().Over().ToValue()pattern with a lambda-based builder that adds compile-time safety (ranking functions requireORDER BY,FILTERonly on aggregates, frames only where valid). It covers ranking, offset (LEAD/LAG), value (FIRST_VALUE/LAST_VALUE/NTH_VALUE), aggregate, statistical, regression/covariance, ordered-set (PERCENTILE_CONT/DISC), hypothetical-set and distribution (MEDIAN, RATIO_TO_REPORT) functions, plus full ROWS/RANGE/GROUPS frames with BETWEEN and EXCLUDE, named windows (DefineWindow/UseWindow), a FILTER clause, NULLS FIRST/LAST, and Oracle KEEP. Existing code using the oldSql.Ext.*window API keeps working unchanged — it's translated onto the new pipeline internally at query time, with no source changes needed. Where a provider doesn't support a requested feature, a clearLinqToDBExceptionis raised at translation time instead of sending invalid SQL. See details below. (#5468) - New fluent entity-level DML APIs.
Upsert(item, …)performs an insert-or-update from a single entity with one configure lambda —.Match((t, s) => …)to pick the key,.Insert(…)/.Update(…)to set insert-only vs update-only columns, plus.When(…),.DoNothing(),SkipInsert()/SkipUpdate()— superseding the older three-expressionInsertOrUpdateoverloads, and it also acceptsIEnumerable<T>andIQueryable<T>sources. New entity-basedInsert(item, …)andUpdate(item, …)take an entity plus a builder where every mapped column is written from the entity by default and.Set/.Ignoreoverlay individual columns (Updatematches on the primary key). All have sync and async variants.Upsertmaps to each provider's native construct —ON CONFLICT(SQLite, PostgreSQL 9.5+),MERGE(SQL Server 2008+, Oracle, DB2, Firebird 2+),ON DUPLICATE KEY UPDATE(MySQL/MariaDB), nativeUPSERT(SAP HANA) — and falls back to a multi-statement emulation elsewhere; settingLinqOptions.UpsertEmulationPolicytoThrowrejects the emulated fallback. Resolves #2528, #4153, and #1480 (as an alternative design). See details below. (#5482) - Query filters can now be named, mirroring EF Core 10's keyed filters. New
HasQueryFilter(string filterKey, …)overloads on the fluentEntityMappingBuilder<T>register multiple independent filters per entity (AND-combined at query time); passingnullfor a filter lambda (with a key) removes that filter. Named filters can also be declared by attribute viaQueryFilterAttribute.FilterKey, alongside the fluent builder. The matchingIgnoreFilters(IEnumerable<string> filterKeys, params Type[] entityTypes)overload disables filters selectively — by key, or by key×entity-type intersection — instead of all-or-nothing. Existing single (anonymous) filters and the parameterlessIgnoreFilters()keep working. See details below. (#5525) - Added
NULLS FIRST/NULLS LASTcontrol to LINQ ordering. NewOrderBy/OrderByDescending/ThenBy/ThenByDescendingoverloads accept aSql.NullsPosition(First/Last/None), and a default placement can be set vianew DataOptions().UseDefaultNullsPosition(...)orConfiguration.Sql.DefaultNullsPosition. Rendered natively where supported (PostgreSQL, Oracle, DB2, Firebird, SQLite, DuckDB, ClickHouse, SAP HANA) and emulated automatically elsewhere (SQL Server, MySQL, MariaDB, Access, Sybase, etc.), with consistent results; it also flows throughDISTINCT/ set operations,DistinctBy/UnionBy/MinBy/MaxBy, indexedSelect, and aggregate ordering. The BCLOrderBy/ThenBy(keySelector, IComparer<TKey>)overloads - which have no SQL equivalent - are now rejected with a translation error instead of being silently ignored. See details below. (#5561) - New opt-in
LinqOptions.PreferClientCalculation(defaultfalse; alsoDataOptions.UsePreferClientCalculation(...),LinqOptions.WithPreferClientCalculation(...), and the globalConfiguration.Linq.PreferClientCalculation). When enabled, computed expressions in the final projection — arithmetic, conditionals, unary operations, and mapped members/methods that don't require server-side evaluation — are evaluated client-side during materialization instead of being emitted as extra SQL columns, restoring the v5 projection behavior. Expressions that require server-side evaluation still translate to SQL. (#5604) - Added server-side UUIDv7 generation — a new
Sql.NewGuid7()extension and translation of .NET 9+Guid.CreateVersion7(), mirroring the existingSql.NewGuid()/Guid.NewGuid()(v4) mechanism. Providers with a native UUIDv7 function emit it server-side (PostgreSQL 18+, DuckDB, ClickHouse, MariaDB); every other provider generates a client-side RFC 9562 v7 GUID. See details below. (#5648)
- The query cache is now bounded and self-managing. Previously each result type kept up to 100 compiled query plans with no global ceiling and no idle eviction, so a long-running application issuing many distinct queries — multi-tenant filters, user-built reports, or frequent
MappingSchemaswaps — could accumulate large numbers of stale cached plans and grow in memory without bound. The cache now enforces a global entry cap and evicts idle entries on a periodic background sweep (rarely-used queries expire within an hour; frequently-used ones are retained longer), keeping memory bounded in long-running and dynamic-query workloads. The cap, idle timeout, and sweep interval can be tuned viaQueryCache.Defaultin theLinqToDB.Internal.Linqnamespace. (#5501) - ClickHouse and YDB now report an unsupported correlated subquery used in expression position (inside EXISTS / IN / a scalar comparison or function argument) with a clean
LinqToDBExceptioninstead of letting the query reach the server and fail with a raw provider error. Simple correlated subqueries that ClickHouse does support continue to work. (#5574) -
DistinctBynow generates nativeSELECT DISTINCT ON (...)on PostgreSQL and DuckDB instead of theROW_NUMBER()emulation, producing simpler SQL. The key selector becomes theONlist and the query'sOrderByis arranged to lead with those keys (as the syntax requires); other providers keep the existing emulation unchanged. (#5630) - DB2, Firebird and Informix now apply a parameter cast per usage rather than marking the parameter as a whole, which removes a redundant nested cast from generated SQL —
Sql.Convert<string, int>(Sql.AsSql(x).Length)on Firebird now rendersCAST(@p AS VARCHAR(8191))instead ofCAST(CAST(@p AS Int) AS VARCHAR(8191)). (#5723)
- A user-registered
IMemberTranslatornow takes priority over the built-in predicate translation for boolean method calls (Contains,Equals,StartsWith, …). Previously a custom translation for these could be ignored; the built-in translation remains as a structural fallback, so predicates inside generic helpers,MergeIntosubqueries, and EF Core query filters still translate correctly. (#5348) - Fixed an
ArgumentOutOfRangeExceptionduring query build when a nestedUnionAllreordered or augmented the projected columns — for example a constant column inserted ahead of a column that then has to move to a higher index. Set-operator column re-indexing now handles the reorder. Reported as #5617. (#5450) - Provider auto-detection now works in
PublishSingleFileself-contained deployments. Previously, building an app withdotnet publish --self-contained -p:PublishSingleFile=truecould break ADO.NET provider detection (for MySQL, SQL Server, SQLite, Oracle, ClickHouse, Access, Informix, Sybase ASE, and SAP HANA), surfacing errors such asCannot load assembly MySql.Dataeven when the app referenced onlyMySqlConnector. Detection no longer relies on the emptyAssembly.Locationvalue that single-file bundles report. (#5489) - Fixed a
NullReferenceExceptionthrown while building a query when a client-evaluated conditional (?:) expression — for example one usingstring.IsNullOrWhiteSpace— had an un-taken branch that would itself throw. The C# short-circuit semantics of?:are now preserved so the un-taken branch is no longer evaluated. (#5544) - Server-side
string.IsNullOrWhiteSpacetranslation now also recognizes U+202F (narrow no-break space) as whitespace, so a value containing only that character is treated as whitespace (matching .NET's whitespace set). (#5544) - Fixed
InvalidOperationException("Member '...' not found") when a column is mapped through a nested member path (e.g.Property(o => o.Sub.Field)or[Column(MemberName = "Sub.Field")]). Such mappings now work in MERGE implicit setters (UpdateWhenMatched/UpdateWhenMatchedAndThenDelete), inOnTargetKey()when the primary key is nested-mapped, and when an inheritance discriminator is mapped via a nested path. (#5545) - Fixed association resolution failing for interface / abstract-base member access reached through a
Select(...)projection (e.g.Contains()over a projected interface filter); follow-up to #5511 (#5548) - Fixed a crash under Native AOT triggered by lambda closures used in queries (#5552)
- Fixed two problems with
ORDER BYexpressions that get lifted from a subquery up to the outer query:- custom ordering built with
Sql.Expr/Sql.Fragmentthat includes a trailing modifier such asNULLS FIRST(e.g. added via anIExpressionPreprocessor) produced invalid SQL — PostgreSQL rejected it with a syntax error; - a computed expression reused in both a subquery column and the outer
ORDER BYcould be emitted referencing the wrong table alias. (#5556)
- custom ordering built with
- Fixed aggregation methods (
Count/Sum/Min/Max/Average) on a captured local collection being translated into a SQL aggregate subquery instead of evaluated on the client (#5557) - Fixed an
InvalidCastExceptionthrown for a query containing aContains(IN) call inside a correlated subquery whose source is filtered by an outer column. (#5558) - Restored
IS NULLsimplification over string concatenation: aWHERE (column + value) IS NULLfilter again generates the simplercolumn IS NULLon null-propagating-concat providers (e.g. SQL Server, Access), instead of testing the whole concatenation for null. (#5567) - Fixed redundant nested case-conversion in generated SQL when calling
.ToLower()or.ToUpper()on a Guid converted to string. The provider's own Guid-to-string conversion already lower-cases its result, so a user-supplied.ToLower()on top produced a doubled wrap (for exampleLCase(LCase(...))on Access orLower(Cast(Lower(...)))on Firebird); the optimizer now collapses these to a single case call. (#5570) - Fixed two problems with custom expression mappings registered through
Expressions.MapMember. A mapped member used to project a correlated aggregate directly - for example a helper method mapped top.Children.Count(...)- previously threw an error during query translation instead of producing the expected subquery; it now translates the same as the equivalent hand-written association aggregate. Separately, a mappedstring.CompareTo/string.Comparewith a null operand could return a wrong result when evaluated in memory (the generated SQL was already correct); that comparison is now correct. (#5577) - Fixed a v6 regression where
[ExpressionMethod]substitutions fired during entity materialization regardless of the attribute'sIsColumnsetting. An[ExpressionMethod]withIsColumn = false(the default) — meant for query-only rewrites that drive server-side SQL and are never evaluated on a materialized client value (e.g.json_each-style table forms, navigation chains, customSql.*helpers) — was incorrectly expanded at materialization and broke. Calculated columns (IsColumn = true) are now expanded specifically during entity construction, whileIsColumn = falsemembers are left as plain column reads (calculated columns declared on inheritance subtypes are expanded correctly too). (#5578) - Fixed a regression where subtracting two
DateTime/DateTimeOffsetcolumns in a projection (e.g.select new { Time = t.FinishedOn - t.StartedOn }, yielding aTimeSpan/TimeSpan?) generated invalid SQL and failed at runtime (or returned wrong results, depending on the provider). The subtraction is now evaluated client-side, preserving full tick precision; the(a - b).TotalDays/TotalHours/... forms continue to translate server-side viaDateDiff. Forcing such a subtraction server-side withSql.AsSql(...)now reports a clear "could not be converted to SQL" error. (#5581) - Fixed wrong results for
NOT IN/ negatedContainsagainst a subquery on providers without correlated-subquery support (e.g. ClickHouse): when the subquery returned aNULLvalue, rows that should have been kept were incorrectly dropped. The subquery membership test now ignoresNULLelements, matching LINQ'sContainssemantics. (#5582) - Fixed an
InvalidOperationException("Called when root is not initialized") thrown at query-build time whenNullable<T>.HasValue(or.Value) was used on a member left unbound by an earlier projection — for example a two-stageSelectwhere the nullable member is never assigned and is then tested with.HasValuein the next projection.HasValuenow correctly resolves tofalsefor such an unassigned (null) member. (#5586) - Fixed an
InvalidCastException("Failed to convert parameter value ... to a Decimal") thrown when a table is LEFT JOINed to a local in-memory collection (e.g. via.AsQueryable()) whose element is a multi-member class and one of its members feeds decimal arithmetic in a later projection. A spurious whole-object column was emitted in the generatedVALUESclause; the join now builds correctly. (#5587) - Fixed an
InvalidCastExceptionthrown when an aggregate — a custom[Sql.Extension(IsAggregate = true)]function (e.g.count_if) or an analyticAverage(…, Sql.AggregateModifier)overload — appeared in one branch of a set operation (UNION ALLetc.) against a constant in the other branch. Such queries now build correctly. (#5619) - The LINQ expression mapping registry (
Expressions.MapMember/MapBinary) is now thread-safe. Registering a custom member/binary mapping concurrently with query compilation (or from multiple threads) could previously corrupt the internal registry; registrations and lookups are now safe under concurrent access. (#5623) - Fixed a
LinqToDBException: Table not foundthrown while building SQL when a.Concat(…)(set-operation) result was.Join(…)-ed to another table used only for filtering — a regression from 5.x. The union now stays a proper derived table and the filtering join binds correctly. (#5629) - Fixed
ORDER BYbeing dropped fromOrderBy(...).Distinct().Take(n)and...GroupBy(...).Take(n)queries, which letTake/Skipreturn arbitrary rows. The ordering is now preserved when every column it references is produced by theDISTINCTprojection or theGROUP BYkeys. (#5632) - Fixed fluent
IsExpressionmapping on a nested property (e.g.c => c.Address.Postcode) throwingLinqToDBException: Can't convert … to expression.at query build. Nested-property computed columns now build and materialize correctly. (#5635) -
OptimizeForSequentialAccessis now a per-context option (LinqOptions.OptimizeForSequentialAccess, withDataOptions.UseOptimizeForSequentialAccess(...)) instead of only a process-global static. This fixes anInvalidOperationException("Invalid attempt to read from column ordinal … With CommandBehavior.SequentialAccess …") that could occur when a cached materialization plan compiled with the option off was reused by a context reading withSequentialAccess(or vice-versa) — sequential and non-sequential plans now occupy distinct query-cache slots. The globalConfiguration.OptimizeForSequentialAccessis kept as a back-compat default. (#5639) - Fixed the fluent
Sql.AnalyticFunctions.Lead(expr, nulls)overload silently dropping itsIGNORE NULLS/RESPECT NULLSargument (it emitted a plainLEAD(expr)); the modifier is now applied, matching theFirstValue/LastValue/Lagoverloads that already did. (#5644) - Fixed a column that has a
ValueConverterbut no explicitDataTyperesolving its database type from the model member type (which usually has none), so it fell back toUndefinedand dropped precision/scale/length facets. The DB type is now resolved from the converter's provider type — for example an F#decimal optionnow maps to the provider'sdecimal(18,10)instead of collapsing to a bareDecimaland truncating scale. (#5645) - Fixed an uncatchable
StackOverflowExceptionthat could crash the process on deeply nested / recursive queries instead of recovering gracefully. The deep-recursion stack guard now probes the remaining stack more frequently, so it reliably switches to its thread-hop fallback (or throws a catchableInsufficientExecutionStackException) before the stack is exhausted. (#5656) - Fixed a concurrency bug where executing the same cached, parameter-dependent query on multiple threads at once could render corrupted SQL — table aliases and column names could be swapped or duplicated, surfacing as
42703 column does not existon PostgreSQL or as wrong results on other databases. Query alias finalization no longer mutates the shared cached statement, so a cached query is now safe to render concurrently. (#5657) - Fixed raw-SQL /
ToSqlQuery()entity materialization that maps result columns by name returning defaults or failing on providers that force aliases on the root SELECT (SqlCe, YDB, Access): the root SELECT now keeps each column's physical name instead of renaming it to the member name, and colliding root columns are given unique aliases (e.g.PersonID/PersonID_1). (#5657) - Fixed the generated SQL differing between the direct and remote (LinqService) execution paths; table aliases are now uniquified per logical source rather than per table-source wrapper, so both paths produce identical aliasing. (#5657)
- Fixed an
InvalidCastException(a regression since 6.2.0) whenLoadWith/ThenLoadwas called on a plainIQueryablethat isn't a linq2db query (e.g.Enumerable.Empty<T>().AsQueryable()). Synchronous enumeration of such a source now passes through to the original query (mirroring EF CoreInclude); async enumeration — and accessing the linq2dbDataContext,GetSqlQueries, or the debug SQL view on it — now raises a clearLinqToDBExceptionrather than the previousInvalidCastException. (#5658) - Raw SQL queries materialized into a record or constructor-based type —
Query<T>(string),QueryToList/QueryToListAsync, etc. — now bind result columns by the same rules as LINQ queries: a member's[Column("some_column")]name is authoritative and a[ValueConverter]on a constructor-bound column is applied. Previously a constructor / positional-record parameter was matched to a result column by parameter name only, so a[Column("some_column")]-mapped member came backnull/default and its[ValueConverter]was never applied. ⚠ Because binding now follows the mapped column name, the previous workaround of aliasing a column to the member name (select some_column as SomeColumn) no longer binds — select the column under its mapped name instead. Duplicate or empty column names in a raw result set are tolerated. (#5659) - Fixed several table-per-hierarchy (single-table inheritance) defects, especially in hierarchies with an abstract intermediate class: sibling subtypes that map the same C# member to different physical columns now read and write correctly; an association declared on a derived type now emits the discriminator on its join (no spurious matches on non-matching rows); a base-typed insert writes shared and abstract-intermediate columns for every sibling subtype; and
OfType<TIntermediate>()over an abstract intermediate now materializes the concrete subtypes instead of throwing "Cannot construct". (#5661) - Fixed enum-column null handling in association joins: an optional association whose join condition involves an enum column emitted
column <> 0instead ofcolumn IS [NOT] NULL(the enum-to-intconversion was compared against0rather than null-checked), which polluted the join condition and could silently drop rows whose enum value equals its zero-valued member. The conversion-wrapped enum null check now correctly generatesIS [NOT] NULL. (#5667) - Fixed a 6.x regression where a recursive CTE built with
db.GetCte<T>(anchor.Concat(recursive))whose projection type had anobject-typed member silently dropped columns from the CTE header — later references to the dropped columns then failed (Invalid column nameon SQL Server,no such columnon SQLite). Astring-typed member worked; onlyobject-typed members triggered it. Union-merged CTE columns now keep their tracking and resolve regardless of member type. (#5680) - Provider version auto-detection (the
AutoDetectdialect path) opened a caller-suppliedDbConnectionto probe the server version and then failed to close it, even though linq2db was the one that had opened it. A connection handed to linq2db closed — e.g. EF Core's shared connection obtained viacontext.CreateLinqToDBConnection()— was opened for the probe and left open, staying pinned, which could break the owner's later operations (for example an EF CoreEnsureDeleted/EnsureCreatedcycle failing with a broken/socket connection). linq2db now closes the probe connection only when it opened it, and leaves an already-open connection untouched. (#5691) - Fixed cached queries producing wrong SQL on re-execution. Provider SQL rewrites could modify the cached statement in place instead of rebuilding it, so the second and later runs of a query saw an already-rewritten statement. Observed on Oracle (
COALESCEcharacter-set handling andVALUES-table queries, including through the remoteLinqServicecontext) and on Informix (casts on a parameter used more than once). (#5723) - Fixed
DistinctByfailing withTable not found for '...'when operators preceded it in the query — most commonly aWhere. On theROW_NUMBERemulation path the preceding query state was dropped, taking the filter with it, and query building then failed. (#5732)
- F#
'T optionand'T voption(value-option) columns now map automatically in thelinq2db.FSharppackage — after.UseFSharp(), option columns round-trip with no manualMappingSchemaconfiguration: the some case (Some/ValueSome) stores the value and the none case (None/ValueNone) storesNULL. Value-typed options such asint optionroute throughNullable<'T>, so none is stored asNULLinstead of the value-type default (previously anint optionNonewas stored as0). Only options over a scalar element type are auto-mapped, and the column's DB type — including facets like decimal precision/scale and string length — is resolved from the element type against the connection's provider schema, so it matches the equivalent non-option column. Auto-mapping is a lower-priority fallback and never overrides mappings you've configured explicitly. (#5624)
- Fixed F# record-copy updates. Both
table.Update(fun r -> { r with Field = v })andquery.Update(predicate, fun r -> { r with Field = v })— including the asyncUpdateAsyncvariants — previously generated anUPDATEthat wrote every column (including the primary key), which some providers reject. Only the changed (non-PK) column(s) are now written. (#5627)
- EF Core 10 keyed query filters and
IgnoreQueryFilters(IReadOnlyCollection<string>)now flow through to linq2db's named query filters. See details below. (#5525) - Many-to-many (skip navigation) associations now translate to SQL. Queries over a many-to-many navigation backed by an implicit join table - e.g.
share.Users.Any(...)and nested forms, plusAll/Count/SelectMany, reverse-direction navigation, andIncludeeager loading - previously failed with "The LINQ expression could not be converted to SQL." Composite keys, self-referencing relationships, explicit join entities with payload, and multiple distinct relationships between the same entity pair are supported (multiple implicit relationships between the same pair throw a clear exception). EF Core 8/9/10; EF Core 3.1 unaffected. See details below. (#5588)
- Fixed a connection leak in the implicit EF Core helpers
ToLinqToDB(),DbSet.ToLinqToDBTable()andDbContext.GetTable<T>(). These create an internal linq2db context that is never disposed, so it held the EF connection open until garbage collection. The internal context now releases the connection after each command (as EF Core itself does), closing only what linq2db opened, so an ambient transaction is unaffected. The publicCreateLinqToDBContext()is unchanged. (#5378) - Fixed a fatal crash on Mono / Android (Native AOT) when reading the EF Core model metadata. Thanks to Tim Haasdyk (#5546)
- Fixed linq2db's query cache missing on every
DbContextwhen EF Core doesn't share its internal service provider across contexts — pooled contexts,EnableServiceProviderCaching(false), or several providers in one app. Each context produced a fresh mapping-schema identity, so every query was recompiled per context instead of being reused. The schema is now shared across contexts of the same model, while different models — including customIModelCacheKeyFactoryand multi-tenant setups — still get separate schemas. (#5695)
- Fixed the
linq2db.LINQPaddriver failing to install from LINQPad's NuGet package manager on macOS/Linux (reported as "No compatible assemblies found"). The driver installs again on every OS; the regression was introduced in 6.2.0. (#5571) - LINQPad driver: fixed the Database Type and Provider dropdowns in the dynamic-connection dialog being clipped on narrower dialog widths; they now fill the available row width instead of using a fixed size. (#5579)
- Scaffolding can emit
[GetSqlDecimal]for SQL Serverdecimalcolumns with precision or scale outside CLRdecimallimits —--sqlserver-decimal-overflow-protection(off by default), orDataModelOptions.GenerateSqlServerDecimalOverflowProtectionwhen driving the scaffolder in code. (#5605) - New
linq2db.clicommands for working against a database directly, aimed at AI agent hosts as well as interactive use:query(one read-only SQL statement → JSON, JSON-table or CSV),execute(one write-capable statement, refused unless the selected profile setsenableExecute),schema(provider-aware object metadata as JSON, with schema/catalog/table filters and a compactnamesdetail level),config-init(create or update a JSON connection profile),credentials(encrypted credential profiles via Windows Credential Manager, scoped to the creating account),skill(prints agent-oriented usage), andmcp— a STDIO Model Context Protocol server exposinglinq2db_info,linq2db_schema,linq2db_query,linq2db_executeandlinq2db_skill. Safe defaults throughout: read-only SQL guardrails onquery,executeoff unless explicitly enabled at both MCP startup and in the profile, and an 8 MiB MCP response cap that truncates on a row boundary rather than emitting invalid JSON. See details below. (#5678)
- New analyzer package
linq2db.Analyzers, with its first ruleL2DB1001. It flags the legacySql.Extwindow-function API —Sql.Ext.<Fn>(...).Over()…ToValue(), i.e.LinqToDB.AnalyticFunctions— as superseded bySql.Window, which is slated for removal in a future major release. Reported atInfoseverity and enabled by default, with a companion code fix ("Convert to Sql.Window API") that rewrites mechanically-convertible chains and supports Fix-All across a document. Aggregates without.Over()are not reported — they aren't window functions, so there's noSql.Windowtarget to migrate to. Documented at L2DB1001. See details below. (#5703) - The analyzer rules ship with the library:
linq2dbnow depends onlinq2db.Analyzers, so they arrive with a directlinq2dbreference or through any satellite package (linq2db.Tools,linq2db.Remote.*,linq2db.Extensions,linq2db.Compat,linq2db.Scaffold,linq2db.EntityFrameworkCore) with no extra reference — on by default. Requires .NET SDK 8.0+ or Visual Studio 2022 17.8+; older hosts skip the rules silently. Severity is configurable per rule, or for every linq2db rule at once viadotnet_analyzer_diagnostic.category-LinqToDB.severity, and<EnableLinqToDBAnalyzers>false</EnableLinqToDBAnalyzers>disables them entirely. Referencelinq2db.Analyzersdirectly only to run the migration rule against an older linq2db (6.1–6.3) when planning an upgrade. (#5720)
- new ClickHouse
GLOBAL ALLjoin hint (JoinGlobalAllHint()/ClickHouseHints.Join.GlobalAll), completing the GLOBAL + strictness join-hint combinations. (#5555)
- a standalone
ALLClickHouse join hint produced malformed SQL (it was matched as a compound prefix rather than a standalone strictness modifier); it now emits correctly. (#5555)
- the compound
All*join-hint aliases (AllOuter,AllSemi,AllAnti, …) are deprecated in favor of the standalone strictness hints (OUTER,SEMI,ANTI, …), matching ClickHouse's actual two-axis strictness (ALL/ANY/SEMI/ANTI/ASOF) + distribution (GLOBAL) syntax. The aliases still work for backward compatibility; recompiling maps them to the corrected standalone hints. (#5555)
- Fixed reading a DB2
DECFLOATcolumn holding an IEEE special value (Infinity/-Infinity/NaN) throwingLinqToDBConvertException/FormatException— such values arise naturally from division by zero inDECFLOAT(e.g.RATIO_TO_REPORTover a zero-sum partition). They now materialize correctly:double/floattargets keep the special value;decimaland integral targets yieldnull(nullable) or the default. Finite values still round-trip exactly. (#5669)
- Added
FirebirdTools.ClearPool(DbConnection)andFirebirdTools.ClearPool(string connectionString)to clear the connection pool for a single Firebird database, complementing the existing process-wideFirebirdTools.ClearAllPools(). Use it to release one database's pooled connections — e.g. after aDROP/CREATEthat Firebird would otherwise block with object TABLE is in use — without evicting every other Firebird pool in the process. (#5689)
- Informix: fixed a nullable-projected
Sum(e.g.Sum(x => (decimal?)x)) over a non-nullable column where the generated null-guard was a no-op (Nvl(x, NULL)) that didn't apply the intended default; the aggregate now behaves as intended. The same no-op null-guard was also fixed in the AccessIIFfold. (#5568)
- Oracle: fixed
DateTimeOffsetvalue handling. The time-zone offset is now preserved when generatingTIMESTAMP WITH TIME ZONEliterals (previously the offset was discarded and replaced with+00:00, corrupting the stored instant), and casts that only change a date/timestamp's precision or add/remove a time zone now emit a plainCASTinstead of malformedTO_TIMESTAMP/TO_DATEcalls.DateTimeOffsetvalues bound to a zone-lessTIMESTAMPcolumn are normalized to UTC. Date/datetime-to-string casts targeting anNChar/NVarChartype now emitTO_NCHAR(rather thanTO_CHAR), andDateOnlyis covered by the same cast path. (#5466) - Fixed an Oracle
UPDATEwith a correlated row-subquery setter (e.g. a non-PK join narrowed by.Single()) generating invalid SQL. The correlated subquery now lifts cleanly instead of leaving a dangling self-reference. Thanks to jods. (#5584) - Fixed long string and XML values being bound as ordinary string parameters, which failed for
OracleXmlTableand other long-string parameter scenarios. A string parameter with no explicit data type whose length reachesOracleOptions.MaxStringParameterLength(new, default4000) is now bound asNText/NCLOB; set it tonullto disable the inference. This applies to raw SQL andDataParametervalues — a LINQ-generated parameter is typed from its column or CLR type, so it never reaches the inference and is unaffected. (#5600)
- Added PostgreSQL 19 support — new
v19dialect (ProviderName.PostgreSQL19), server-version detection and config-string matching. On PostgreSQL 19 theFIRST_VALUE/LAST_VALUE/LEAD/LAG/NTH_VALUEwindow functions now emitIGNORE NULLS/RESPECT NULLSin PostgreSQL's SQL-standard outside-parens form (FIRST_VALUE(x) IGNORE NULLS), instead of the Oracle-style inside-parens form it rejects with a42601syntax error. (#5644) - PostgreSQL 11 and 12 support — new
v11/v12dialects (ProviderName.PostgreSQL11/PostgreSQL12), server-version detection and config-string matching, plus version-aware gating of window-function capabilities: constructs a given server doesn't support — frameGROUPS/EXCLUDEbefore 11,WITHIN GROUPordered-set and hypothetical-set aggregates before 9.5,AS [NOT] MATERIALIZEDCTEs before 12 — are now rejected up front with a descriptiveLinqToDBExceptioninstead of emitting SQL the server rejects. (#5687)
- Fixed PostgreSQL schema discovery misclassifying identity columns: a
nextval(...)call embedded in a larger default expression (e.g.'PREFIX_' || nextval(...)) is no longer treated as a native identity column — only a direct serial-styleDEFAULT nextval(...)still is. A true identity column is preferred when present, and when a table has multiple sequence-backed defaults a primary-key column is selected first. (#5647)
- New
[GetSqlDecimal]attribute for SQL Serverdecimalcolumns whose precision or scale falls outside the CLRdecimalrange. Reading such a column previously threwOverflowException; with the attribute the value is read through SQL Server's ownSqlDecimaland its scale reduced to fit, which can round away least-significant digits. A value whose magnitude still exceedsdecimal.MaxValuecontinues to throw. Opt-in per column, and applied only when the provider is SQL Server. (#5605)
- Fixed schema load returning no views at all on SQL Server 2016+ when the
IgnoreSystemHistoryTablesoption was enabled — the temporal-history filter excluded views along with history tables, so scaffolding, T4 andlinq2db.cliproduced a model with no views. AffectsGetSchemaOptions.IgnoreSystemHistoryTables, the scaffold--ignore-system-history-tablesoption, and the CLIschemacommand. (#5734)
- SQLite schema provider (
GetSchema()) now returns tables and views in a deterministic, platform-independent order; previously the order followed whatever the native SQLite library returned and could differ between platforms and SQLite versions. (#5606)
- Sybase ASE now emits the ANSI
||operator for string concatenation instead of the Transact-SQL+operator, matching the SQL shape used by the other||providers. Results are unchanged -||behaves identically to+on ASE (neither propagates NULL, and both still cast non-character operands), so this is a SQL-text-only change. (#5569)
- Sybase ASE:
Sql.Concatno longer emits redundantIS NULLguards on operands that can't be NULL (string literals, non-nullable columns), producing much cleaner SQL. Regression introduced in a 6.4.0 preview. (#5566)
- The YDB provider is now fully implemented and supported (previously experimental) — schema API, CLI scaffolding, LINQPad driver, and broad LINQ/translation coverage. See details below. (#5564)
var query =
from c in db.Companies
orderby c.Id
select new
{
c.Id, c.Name,
Departments = db.Departments
.Where(d => d.CompanyId == c.Id)
.Select(d => new { d.Id, Employees = db.Employees.Where(e => e.DepartmentId == d.Id).ToList() })
.ToList(),
};
query.WithKeyedLoadStrategy().ToList(); // buffer parents, load children by key
query.WithUnionLoadStrategy().ToList(); // single UNION ALL CTE across all levelsWith KeyedQuery the parent query runs once and each child level loads with WHERE key IN (…):
SELECT [Id], [Name] FROM [Company]
SELECT ... FROM [Department] WHERE [CompanyId] IN (1)
SELECT ... FROM [Employee] WHERE [DepartmentId] IN (1, 2)CteUnion instead emits a single query whose CTEs carry every level and are combined with UNION ALL (marked AS MATERIALIZED on PostgreSQL 12+, SQLite 3.35+, and ClickHouse where a CTE is referenced more than once).
var query =
from t in db.Employees
let wnd = Sql.Window.DefineWindow(f => f.PartitionBy(t.Department).OrderBy(t.HireDate))
select new
{
RN = Sql.Window.RowNumber(f => f.PartitionBy(t.Department).OrderBy(t.HireDate)),
RunningSum = Sql.Window.Sum(t.Salary, f => f.UseWindow(wnd)),
NextSalary = Sql.Window.Lead(t.Salary, 1, 0m, f => f.UseWindow(wnd)),
AvgActive = Sql.Window.Average(t.Salary, f => f.Filter(t.IsActive).UseWindow(wnd)),
MinFirst = Sql.Window.Min(t.Salary, f => f.KeepFirst().OrderBy(t.HireDate).PartitionBy(t.Department)),
};Frames use explicit boundary direction, so same-direction frames are expressible:
Sql.Window.Sum(t.Value, f => f.OrderBy(t.Id).RowsBetween.ValuePreceding(1).And.CurrentRow)
Sql.Window.Sum(t.Value, f => f.OrderBy(t.Id).RowsBetween.Unbounded.And.Unbounded.ExcludeTies())FILTER (WHERE …) is native on PostgreSQL and emulated via CASE WHEN elsewhere; NULLS FIRST/LAST is native on PostgreSQL, Oracle and Firebird 3+ and emulated elsewhere. Configured across SQL Server, PostgreSQL, Oracle, MySQL/MariaDB, ClickHouse, SQLite, Firebird, DB2, SAP HANA, Informix, YDB, Access, SqlCe and Sybase — unsupported features raise a descriptive exception rather than emitting invalid SQL.
// Upsert — insert or update a single entity
db.Users.Upsert(user, u => u
.Match ((t, s) => t.Id == s.Id)
.Insert(i => i.Set(x => x.CreatedAt, () => DateTime.UtcNow))
.Update(v => v.Set(x => x.UpdatedAt, () => DateTime.UtcNow)));
// Upsert — bulk from a collection or query
db.Users.Upsert(items, u => u.Match((t, s) => t.Id == s.Id)); // IEnumerable<T>
db.Users.Upsert(query, u => u.Match((t, s) => t.Id == s.Id)); // IQueryable<T>
// Entity Insert / Update — column values come from the entity; .Set / .Ignore overlay
db.Users.Insert(user, b => b.Set(x => x.CreatedAt, () => DateTime.UtcNow).Ignore(x => x.Notes));
db.Users.Update(user, b => b.Set(x => x.UpdatedAt, () => DateTime.UtcNow)); // PK matchThe entity Insert / Update overloads compile to the existing single-statement INSERT / UPDATE and work on every provider, including entity types without a public parameterless constructor (positional records, ctor-only DTOs).
builder.Entity<Order>()
.HasQueryFilter("soft-delete", (o, dc) => !o.IsDeleted)
.HasQueryFilter("tenant", (o, dc) => o.TenantId == ((MyDb)dc).TenantId);
// disable just the tenant filter for this query
db.Orders.IgnoreFilters(new[] { "tenant" }).ToList();
// disable a filter only for specific entity types
db.Orders.IgnoreFilters(new[] { "soft-delete" }, typeof(Order)).ToList();Control where NULL values sort, per ordering key:
// Place NULLs last for this key
db.Table.OrderBy(x => x.Value, Sql.NullsPosition.Last)
.ThenBy(x => x.Id);
// NULLs first on a descending key
db.Table.OrderByDescending(x => x.Value, Sql.NullsPosition.First);
// Default placement for every ordering key that doesn't specify one
var options = new DataOptions().UseDefaultNullsPosition(Sql.NullsPosition.Last);
// or globally:
Configuration.Sql.DefaultNullsPosition = Sql.NullsPosition.Last;Use Sql.NullsPosition.None to opt a single key out of the configured default. The position is rendered as a native NULLS FIRST / NULLS LAST token where supported and emulated with a leading CASE key elsewhere, so the result is the same regardless of provider.
The experimental YDB provider is now first-class. Provider name: YDB. Supported on net8.0, net9.0, net10.0.
Supported features:
- Full CRUD with the usual LINQ surface
- CTE, window/analytic functions,
IS DISTINCT FROM, row-constructor comparisons (equality / comparison /BETWEEN/IN) -
RETURNINGfor identity columns - Schema introspection (tables, columns, primary keys)
- Bulk copy: native appender (
BulkUpsert) with automatic fallback to multi-rowINSERT -
string.Join/StringAggregatetranslation - Temporary tables (
CREATE ... IF NOT EXISTS/DROP ... IF EXISTS) - Scaffold using the
linq2db.clitool - LINQPad support
Skip navigations backed by an implicit join table now work through ToLinqToDB():
// EF Core model: Share <-> User many-to-many via skip navigation
var shares = ctx.Shares
.Where(share => share.Users.Any(u => u.Name == "admin"))
.ToLinqToDB()
.ToList();Previously threw "The LINQ expression could not be converted to SQL." Include eager loading of the navigation is also supported. Known limitation: an entity whose key is field-mapped or shadow (no CLR property) cannot be used as the query root for eager loading.
var id = db.GetTable<Person>().Select(_ => Sql.NewGuid7()).First();
var id2 = db.GetTable<Person>().Select(_ => Guid.CreateVersion7()).First(); // .NET 9+Native server-side functions: PostgreSQL 18+ uuidv7(), DuckDB 1.3.0+ uuidv7(), ClickHouse 24.5+ generateUUIDv7(), MariaDB 11.7+ UUID_v7(). PostgreSQL is version-aware — below 18 it falls back to client-side generation. For DuckDB, ClickHouse and MariaDB the native function is emitted unconditionally (linq2db doesn't probe the server version), so targeting a server older than the function's introduction raises a server-side error rather than falling back. Providers without any native generator always produce the v7 GUID client-side.
linq2db.cli can now read and query a database directly. For agent hosts, mcp is the intended integration; query covers direct invocation where MCP isn't available or allowed.
Point the MCP server at a config file that names the database profiles:
{
"mcp": {
"title": "Audiobooks Database",
"description": "Application database containing audiobooks, authors, narrators, users, and listening history."
},
"default": {
"provider": "PostgreSQL",
"connectionStringEnv": "AUDIOBOOKS_CONNECTION_STRING"
}
}Agents work linq2db_info (profiles, providers, dialects, safety rules, response limit) → linq2db_schema (tables, views, columns, keys, relationships) → linq2db_query (one read-only statement), with linq2db_skill returning the full guide. The same profiles drive direct use:
dotnet linq2db schema --detail-level names
dotnet linq2db query --sql "select count(*) from Orders" --output json-table
Prefer connectionStringEnv to a literal connection string — a literal is written into the generated config and warns on stderr. Register the executable once per project or database domain, each with its own --config, so agents get a clear boundary. execute is refused unless the profile sets enableExecute and MCP was started with --enable-execute-tool. CSV output is for machine processing only and deliberately does no spreadsheet escaping, so a value starting with =, +, - or @ may be read as a formula — use json or json-table for untrusted data.
linq2db now ships Roslyn analyzers with the library. The first rule, L2DB1001, flags the legacy Sql.Ext window-function API, and a code fix migrates it:
// reported by L2DB1001
long M(int x) => Sql.Ext.RowNumber().Over().PartitionBy(x).OrderBy(x).ToValue();
// after "Convert to Sql.Window API"
long M(int x) => Sql.Window.RowNumber(f => f.PartitionBy(x).OrderBy(x));The rule reports at Info and only fires on chains containing .Over() — a plain Sql.Ext.Sum(x).ToValue() aggregate is not a window function and has no migration target, so it is left alone. Fix-All rewrites every flagged chain in a document in one pass. A chain that has no mechanical equivalent, such as one carrying .Filter(...), is reported but not rewritten.
Severity is settable per rule, or for every linq2db rule at once:
dotnet_diagnostic.L2DB1001.severity = warning
dotnet_analyzer_diagnostic.category-LinqToDB.severity = errorTo turn the rules off entirely:
<PropertyGroup>
<EnableLinqToDBAnalyzers>false</EnableLinqToDBAnalyzers>
</PropertyGroup>Requires .NET SDK 8.0+ or Visual Studio 2022 17.8+; older hosts skip the analyzers silently rather than failing the build. Referencing linq2db.Analyzers directly is only needed to run the migration rule against linq2db 6.1–6.3 when planning an upgrade.
LinqToDB
-
#3040: added
Enum.HasFlagtranslation to SQL -
#4325: @darko1979 added support for
IgnoreConflictsoption toMultipleRowsmode ofBulkCopyAPI forMySql,MariaDB,PostgreSQLandSQLite -
#5154: fix
InvalidOperationExceptionfromToSqlQuerywhenSqlQueryDependentParamsattribute used in mappings, obsoleteSqlQueryDependentParamsAttribute -
#5302: fix query caching issue for
PostgreSQLwith array parameters. Array,List<T>andIReadOnlyList<T>types now recognized as scalars forPostgreSQL -
#5309: [SQL Server][Firebird] fix conversion to date for expression with
DbType="some_type"set in mappings -
#5323: [PostgreSQL, ClickHouse, DuckDB, SQLite] add explicit configuration API for
CTEmaterialization usingAsCteoverload with configuration builder parameter. Examples:AsCte(c => c.IsMaterialized())AsCte(c => c.IsMaterialized(false))AsCte(c => c.IsMaterialized().HasName("custom_cte_name"))
- #5355: fix issue with associations discovery on interfaces
- #5404: fix SQL generation for subqueries, that select nullable aggregates using non-null returning API
-
#5413: fix
UPDATE FROMtranslation regressions -
#5427: fix remaining issues with
nullhandling byValueConverterfor non-nullable value type -
#5429: fix
StackOverflowExceptiondue to use ofAsQueryablecalls -
#5434: fix value converters support in
Sql.Row -
#5443: [Oracle] improve
COALESCEparameter type inference - #5444: [ClickHouse] add missing whitespace before table hint
-
#5445: fix predicate optimization for
NULLchecks - #5447: fix SET operators flattening
- #5454: type conversion handling fix
-
#5457: fix too aggressive column removal for
CTE - #5458: fix issue with member access translation for SET columns
-
#5463: several fixes to [Create/DropTable] APIs
-
#798: implement
DropTable(throwExceptionIfNotExists: false)parameter to hide only non-existing table errors, not all errors. Thanks to Carlos Salazar for PR - [Oracle] fixed issue when drop of global temp table did nothing if table had data. Now it will truncate table data before drop
- [SAP HANA] handle table not found errors on drop on SQL level for
throwExceptionIfNotExists: false - [DB2][Firebird][SAP HANA][Oracle] properly escape sql statements in
EXECUTEblocks, generated on table create/drop operations
-
#798: implement
-
#5480: fix query caching issues with
FromSqlqueries -
#5504: internal refactoring of string concatenation. Many translation bugs fixed, added support for missing
string.Concatoverloads -
#5505: don't apply
ValueConverterto database-sourced values in UPDATE setters - #5510: fix interface member access translation issue
-
#5515: review and improve
TrimStart/TrimEndoverloads mappings for all providers - #5519: [Access] fix re-surfaced compatibility issues with non-EN locales, fix issue for boolean conversion for read from DB could be applied in wrong places
-
#5522: fix exists over set (e.g.
EXISTS (... UNION ...)) queries generation
Closes #5424.
New overload of AsQueryable lets you choose how each column of an IEnumerable<T> is rendered into the VALUES (...) clause - as SQL parameters or inlined literals - with per-column overrides:
data.AsQueryable(db, b => b.Parameterize())
data.AsQueryable(db, b => b.Inline())
data.AsQueryable(db, b => b.Parameterize().Except(p => p.Id))
data.AsQueryable(db, b => b.Inline().Except(p => p.Address.Zip))The builder is type-safe: Parameterize() / Inline() must come first, after which only Except(...) is available - invalid combinations don't compile.
Provider notes:
-
DB2: parameter cells inside
VALUESare wrapped inCAST(@p AS <type>)to satisfy SQL0418N. -
ClickHouse: parameterized
VALUESis not supported and is skipped.
Closes #5436.
Server-side translation of DateTime.Now, DateTime.UtcNow, DateTimeOffset.Now, and DateTimeOffset.UtcNow is now distinct per variant, so providers that store offset (Oracle, PostgreSQL, Firebird 4+, DB2 z/OS, …) preserve timezone information instead of silently dropping it.
Behavior:
- Providers with native timezone support emit the correct expression for each of the four variants.
- Providers without timezone support don't error —
DateTimeOffset.Now/UtcNoware gracefully downgraded to theirDateTimeequivalents. -
Sql.CurrentTimestamp/Sql.CurrentTimestamp2are now XML-documented.
Bug fixes uncovered along the way:
-
Oracle:
DateTimeOffset.Nowno longer round-trips throughsys_extract_utc, which was discarding the offset and corruptingTIMESTAMP WITH TIME ZONEwrites. -
SQLite:
DateTime.Nowpreviously produced UTC time; now correctly returns local.
Thanks to @stdray for implementing it.
Closes #5451.
New first-class provider for DuckDB — an in-process analytical database with PostgreSQL-compatible SQL — built on top of DuckDB.NET.
Provider name: DuckDB. Supported on net8.0, net9.0, net10.0.
Supported features:
- Full CRUD with the usual LINQ surface
- CTE, window/analytic functions,
LATERAL(CROSS/OUTER APPLY),IS DISTINCT FROM, row-constructor comparisons - SQL
MERGE(WHEN MATCHED / WHEN NOT MATCHED) -
INSERT ... ON CONFLICT DO UPDATE/NOTHING(InsertOrUpdate) -
RETURNINGfor identity columns - Schema introspection (tables, columns, primary keys)
- Bulk copy: multi-row
INSERTand nativeDuckDBAppender(provider-specific) with automatic fallback -
STRING_AGGtranslation forstring.Join/StringAggregate - Temporary tables (
CREATE IF NOT EXISTS/DROP IF EXISTS) - Scaffold using
linq2db.clitool - LinqPAD support
LinqToDB for EntityFramework
-
#5439: [SqlServer] detect fields, defined using
UseSequenceAPI, as identity fields
LinqToDB F# Support
-
#5430:
-
#5428: fix compatibility with
FSharp.Core10.1.x - fix record mapping issues for members with case-only name distinctions
-
#5428: fix compatibility with
LinqToDB CLI
PR #5539.
linq2db.cli now ships as per-RID tool packages (.NET 10 SDK feature). dotnet tool install -g linq2db.cli auto-selects the variant matching your SDK architecture. RIDs: win-x64, win-x86, win-arm64, linux-x64, linux-arm64, osx-arm64, osx-x64.
Bitness is fixed at install time, not per-invocation. Use dotnet tool install -g linq2db.cli --arch x86 for 32-bit. Only Microsoft.Jet.OLEDB strictly requires win-x86; Microsoft.ACE.OLEDB, SQL Server Compact Edition, and SAP HANA just need the tool bitness to match the installed driver bitness. To keep both x86 and x64 available, install each via --tool-path <dir> (-g allows only one).
The Access scaffold now errors with a clear x86-variant hint when the connection string requests Jet and the current process isn't 32-bit, instead of failing deep inside the OLE DB factory load.
LinqToDB
-
#5284: multiple fixes to generated SQL
- #5283: fix translation issues for nested associations
- fix issues with
UPDATEqueries with sub-queries in setters - fix
COALESCEtranslation - improve joins optimization and unnesting, detect more cases when
LEFT JOINcould be promoted toINNER JOIN
-
#5411: fix behavior of
CompareNulls.LikeSqlExceptParametersoption -
#5416: fix
nullconversion to mapped enum -
#5417: ignore table filters for
DropandTruncatetable operations -
#5420: fix invalid SQL generation for
INSERTwith sub-query setters in some cases -
#5423: fix cases where
ORDER BYgenerated in subqueries, that doesn't support it
LinqToDB LINQPad Driver
- #5421: re-fix issue with settings dialog crashing on opening
LinqToDB
-
#5227: [ClickHouse] fix compatibility with
ClickHouse.Driver0.9.0 - #5256: fix invalid SQL generation for nested aggregations
-
#5258: binary/unary operators mapping improvements
- #5254, #5259: fix regressions in handling of custom operators in mapping
- add/fix support for custom operators mapping. Now you can map them using
Sql.ExpressionAttribute,MethodExpressionAttributeorIMemberTranslator(you can see mapping examples in tests). Note that in general you don't need to map custom operators if their logic follow logic of mapped binary or unary operation. But if it implements non-standard behavior, which you want to reproduce n SQL, then you must provde corresponding mapping forLINQ to DB
-
#5259: adding conversion to
DataParameterto mapping schema for struct type will automatically add it also for nullable struct type if such conversion is not registered already - #5262: some internal optimizations
-
#5263: fix
Sql.CurrentTimestamp2translation regression -
#5264:
- fix
ToStringimplementation for string-based enums - obsolete
bool Configuration.UseEnumValueNameForStringColumnsoption as it doesn't have any effect - improve performance of enum mapping
- [Oracle] map
DataType.NVarCharto ``NVARCHAR2type and fix discovered issues withNVARCHAR2` handling
- fix
- #5266: fix mapping of composite properties with overlapping names
-
#5268: remove unnecessary subquery nesting for
INpredicate query - #5269: don't force translated methods conversion to SQL if they could be evaluated on client as parameters or literals
- #5272: [DB2][Firebird] add decimal type facets population from value
- #5274: fix support for inhertance mapping of hierarchies wth 16+ types
-
#5285: fix scalars support by
FromSqlAPI -
#5289: fix
InsertOrUpdateAPI use for tables with query filter -
#5291:
-
#5286: implement bitwise not (
~) translation for all providers - improve parameter database type inference for unmapped types with mapped underlying type (e.g. enums or nullable structs)
- [Access][MySQL] fix bitwise OR (
|) operator precedence - fix/improve some binary operation optimizations
-
#5286: implement bitwise not (
-
#5297:
Sql.DateAddwill not acceptDayOfYearandWeekDaydate part argument values anymore. Before they were treated in same way asDaydate part value -
#5301: fix
ArgumentException : must be reducible nodeerror -
#5304: fix handling of entites that implement
Enity : IEnumerable<Entity>interface - #5307: improvements to SQL generation for complex queries
-
#5310: fix column mappings discovery for
OUTPUT/RETURNINGspecial tables -
#5314: fix merge if
IgnoreFilterscalls - #5317: fix association handling regression
- #5320: [SQL Server] fix non-ASCII descriptions load by Schema API
-
#5321: improve/fix translation of
Convert.To*/Sql.ConvertAPIs to SQL-
#5298: fix
Convert.To*calls with dynamic properties
-
#5298: fix
- #5328: fix nullability calculation for aggregate in subqueries
-
#5332:
-
#5325: add
DateTime.UtcNowproperty mapping - fix convert operation translation issues
-
#5325: add
-
#5336: fix
Cast<T>operator translation -
#5340: fix issue with subqueries handling in
UPDATE - #5341: fix nullability of join conditions for optional associations sequence
-
#5344: fix found issues with complex CTE translations, improve CTE aliases generation for
ClickHouse -
#5350: correct return value database type for some date diff operations, fix typo in SQL for diff in months for
PostgreSQL -
#5351: fix
ValueConvertersupport inUPDATEqueries, improve associations/subqueries translation forUPDATE - #5356: fix unused joins detection issues for nested joins
- #5357: [PostgreSQL] add timeout option support for native bulk copy
-
#5361: fix threading issue for mapping types with non-public mapped members, including
Storagemembers -
#5362: fix
GroupBytranslation -
#5366: fix SQL generation for queries with
DISTINCTandORDER BYover expression - #5368: support aggregation sub-queries inside non-table queries
-
#5369: add support for translation of following
IEnumerable/IQueryablemethodsCountByIndex-
MaxBy/MinBy(overload with comparer not supported) -
ExceptBy/UnionBy/IntersectBy(overload with comparer not supported)
-
#5371: fix issue with name of parameter ignored when provided by
DataParameter -
#5373: fix translation of aggregation function calls with
AsEnumerable/AsQueryablecalls in chain -
#5379: [SQLite] don't generate
CASTto guid as it mess with SQLite affinity inference - #5381: don't remove subqueries with aggregates if outer query has complex clauses that could affect aggregation
-
#5382: fix
CTEsupport forDELETEandUPDATEqueries -
#5383: fix hint API use with
ToSqlQueryhelper -
#5392:
-
#5390: don't generate precision/scale for
DateTime.Datetype - [Access][SQL Server 2005] don't generate precision/scale for
DateTimetype
-
#5390: don't generate precision/scale for
- #5398: fix handling or conversion of one enum type value to value of other enum type
-
#5401: [ClickHouse] add support for
ClickHouse.Driver1.x provider versions. We recommend to enableReadStringsAsByteArrays=trueoption, especially if you work with binary data to avoid data loss onbinary->utf8->binarytranslations
- implement
string.Jointranslation - fix
ORDER BYover aliased column - fix translation of some string-related APIs: padding, replace, indexof, substring
- #5273: significantly reduce stack use by expression and query visitors
- #5270: support switching to additional thread(s) by visitors if there is not enough stack on current thread.
Number of additional threads to use configured using int LinqToDB.Common.Configuration.TranslationThreadMaxHopCount option:
- default value is set to
5 - negative values (e.g.
-1) will disable feature andStackOverflowExceptionwill be generated in case of stack end -
0will not use additional threads, but still test remaining stack space and generateInsufficientExecutionStackException, which could be intercepted - values greater than
0will use up to N threads before throwingInsufficientExecutionStackExceptionexception if this amount is still not enough
We don't recommend to set this option to bigger values as it could lead to performance issues and thread pool starvation if you hit some bug with infinite recursion.
LinqToDB for EntityFramework
- #4668: fix too aggressive inheritance detection
-
#5318: fix mapping of
PostgreSQLenums when nullable enum type used (SomeEnum?). Thanks to @denis-tsv for PR - #5388: fix value converters use for constant values
Scaffold T4
-
#5252: [SQL Server 2025]
JSONandVECTORtypes support -
#5255: fix issues when
NotifyPropertyChangedtemplate used with scaffold
Scaffold CLI
-
#5281: [SQL Server 2025]
JSONandVECTORtypes support
LinqToDB
-
#4816: [SQL Server] fix separator parameter type for
STRING_AGGto be based on type of first argument -
#5233: add support for .NET 10
LeftJoinandRightJoinoperators -
#5236: fix exception converting null value of
Nullable<T>type to another type using non-nullable converter - #5237: fix nuget explorer warings for packages (non-functional change)
-
#5239: fix incorrect update translation with
string.Joinsetter expression -
#5240: [SQL Server < 2025] fix v5 compatibility by mapping
DataType.JsontoNVARCHAR(MAX) - #5244: fix support for non-array collection parameters
LinqToDB LINQPad Driver
Fore release notes and migration notes see page.
This #5161 maintenance release contains no functional changes, improvements, or bug fixes. Only third-party NuGet dependencies have been updated to their latest compatible versions.
- Updated third-party dependencies to improve long-term compatibility and security.
- Most Microsoft packages have been upgraded to version 9.0.10.
- No modifications were made to LINQ to DB core libraries or behavior.
- Intended for users who continue to rely on the stable 5.x branch in production environments.
LinqToDB
-
#4445: [PostgreSQL] improve performance of native
BulkCopy. Thanks to @AndreyShipunov for PR -
#4456: [SQLite] Add optional
extensionparameter toSQLiteTools.CreateDatabaseAPI to specify extension of created database file instead of hardcoded.sqlite. Thanks to @alexey-leonovich for PR -
#4457: Fix connection leak issue with
DataContexttransactions/eager load when context used with auto-released connection without context disposal
LinqToDB
- #4005: adds metrics collection API
-
#4217: fixed
SQLgeneration of unnecessaryIS NOT NULLchecks for some of nullable boolean comparisons -
#4252: add new setting
UseEnableConstantExpressionInOrderBy(bool)to allow constants inORDER BYclause to sort using ordinals. Note that we don't recommend to use it as we don't give guaranty over column order in generated querySQL -
#4327: fix issues with
nullhandling inIN (sub-query)/EXISTSclauses -
#4337: fix 5.3.0 regression
LinqException: ...TransparentIdentifier... cannot be converted to SQL. -
#4341: mark configuration API methods with
[Pure]attribute to highlight that they doesn't modify options object. Thanks to @curllog for PR -
#4368: add support for one-way conversions registration using
mappingSchema.SetConvertExpression.SetConvertermethods using newconversionType = ConversionType.[From/To]Databaseparameter -
#4371: fix multiple issues where
CurrentCultureused instead ofInvariantculture- #3783: fix issue with non-SQL compatible negative literals generated for some cultures
-
#4378: fix
BulkCopyOptionscopy constructor - #4383: fix inherited classes support in eager load
-
#4385: [Oracle] fix
DateOnlysupport in array-bound bulk copy mode - #4387: [NativeAOT] fixed couple of NativeAOT issues. Note that we still doesn't support NativeAOT officially
-
#4389: [ClickHouse] fix bulk copy support with
ClickHouse.Client6.8.0+ provider - #4398: fix rare race conditions in connection options creation logic
- #4403: [Oracle] fix use of fixed-size buffer in multiple-rows bulk copy mode
- #4415: fix regression in nullable aggregated scalar sub-queries handling
-
#4426: fix
NullReferenceExceptiondue to race conditions in context logging when user change trace levels
LinqToDB Configuration
-
#4326: fix incorrect registration logic for
AddLinqToDBContext<TContext, TContextImplementation>()overload
Scaffold T4
- #4375: emit procedures and functions ordered by name
Scaffold CLI
- #4373: fixed incorrect regular expression examples in help. Thanks to Michel Bretschneider for PR
- #4428: add .NET 8 tool build
LinqToDB
- #4313: fix regression in Npgsql 7- support, introduced by 5.3.1 release
LinqToDB
- #4309: fix compatibility with Npgsql 8
LinqToDB
-
#3273: [Oracle] Prefer single
COALESCEfunction over multiple nestedNVLfor calls with 3 or more parameters. Thanks to @ddas09 for PR -
#4122: log elements of collection-typed query parameters (e.g. arrays). By default only first 8 elements logged. Use
Configuration.MaxArrayParameterLengthLoggingsetting to change this limit - #4168, #4174: fixed issue with linked server name being ignored by multiple APIs when only server name passed to API as input parameter
- #4172: [Oracle] fix SQL, generated empty string comparison. Thanks to Divyansh Bhatia for PR
- #4175: fix issue with conditional expressions parsing in output/returning clause. Thanks to Kasper Fabæch Brandt for PR
- #4176: [Access] removed wrong identifier escaping logic, when identifier with dot in name was split into multi-component identifier
-
#4182: fix table attributes support for
MergeWithOutputIntooutput table. Thanks to Kasper Fabæch Brandt for PR -
#4196: fixed
nullvalues support forvalue IN (subquery)syntax. Added new optionPreferExistsForScalarto configure generated SQL for scalar subquery conditions. This feature is useful for databases (e.g. ClickHouse), which doesn't support correlated sub-queries by converting it to non-correlated one.-
PreferExistsForScalar = true:EXISTS (SELECT * FROM sequence WHERE sequence.key = value) -
PreferExistsForScalar = false(default):value IN (SELECT sequence.key FROM sequence)
-
- #4201: support associations with different key types on both sides
- #4202: fix issues with sub-query hints in SET queries
- #4203: fix issue with query hints in subqueries
- #4204: fix issue with optimization of subquery with grouping
- #4210: fix nullability tracing for ternary expressions
- #4219: [Oracle] limit generated query parameter length to 30 characters for Oracle 12+ temporary while we don't have explicit support for 12.2+ Oracle dialects
- #4228, #4254: fix regression in parameter names generation
- #4229: fixed issue, when cached query could hold reference to initial data context object, preventing it from garbage collection. This could lead to excessive memory use by query cache (sometimes huge)
- #4256: fix issue with non-nullable constant values in sub-query projection to nullable projection field/property
-
#4257: enable support for
IDataContext.CloseAfterUse = truecontext flag inBulkCopyAPI - #4261: fixed issue with embedding of enumerable collections with long path to collection
-
#4263: [NativeAOT] fixed issue with
Expression.DebugViewtrimmed away -
#4267: [NativeAOT] implemented workaround for
NativeAOTissue withGetInterfaceMapAPI -
#4268: changed
DataConnection.WriteTraceLineConnectionsetter accessibility to protected to allow direct assignment from child classes. Thanks to @Metadorius for PR - #4275: some internal memory/performance optimizations to entity model build
-
#4280: fixed exception when
Update<TBase>(derivedInstance)API called for entity with inheritance mapping - #4285: [PostgreSQL] fixed issues in identifier quotation logic
- #4299: fix potential issue with default struct constructors
-
#4302: [Access] implement missing conversion to SQL
bool
Scaffold
-
#4131:
- [T4] fix Oracle templates, broken by 5.0 release
- #4058: [T4] fix issues with identifiers generation process steps, when C# keyword check applied before final name generated for some identifier types
-
#4134: [CLI] add
add-init-contextoption to manage generation ofInitDataContextpartial method on context -
#4255: [CLI] fixed multiple issues with parsing of generic types by
ITypeParserimplementation - #4278: [T4] we decided to cancel obsoletion of T4 nugets (scaffold cli utility is still recomended way to scaffold database model)
LinqToDB
-
#4043: add missing support for column converters (
IValueConverter) byExecute[Async](string sql)API - #4146:
Scaffold CLI
- #4127: fix binding of output parameters for synchronous mappings of stored procedures
LinqToDB
-
#4025: fix issue with
object->DataParameterconversion being ignored -
#4074: improve discard of invalid
ORDER BYcolumns from joined subqueries -
#4090: fix nullability tracking for
OUTER APPLYcolumns - #4098: fix issues with missing columns for queries with join to subquery
- #4107: fix merge keys selection into CTE for merge-into-cte queries
-
#4113: fix regression in handling properties, which hide interface implementation with
newkeyword -
#4124: fix database provider detection for
ProviderName.MariaDBname
Scaffold CLI
- #4111: fix scaffold of table functions in separate schema class
We started our own Discord server. Invite could be found here.
LinqToDB
- #3034: fix mapping of inherited interfaces for interface mapping
-
#3776, #3895, EF#213, EF#316: [PostgreSQL] fix issue with
DateTimevaluesKindnormalization, when it was converted toUnspecifiedfor column oftimestamp with time zonetype. If you still have this issue, check that your column has type specified. - #4031: Improve detection of interface property implementation for mapping
-
#4045: [Oracle][PostgreSQL] fix issue with connection string parameter ignored by
PostgreSQLTools/OracleToolsin some methods -
#4046: Apply
DataParameterconversions to parameters in more cases -
#4055: [MySQL] fix trailing hint generation for
INSERTqueries (e.g.INSERT ... SELECT ... FOR UPDATE) - #4065: [Firebird] fix incorrect SQL generation for parameter-less stored procedure, called as table function
-
#4066: [ClickHouse] add helpers to specify join hints,
FINALmodifier andSETTINGSclause (see tests for usage examples) - #4070: [ClickHouse] fixed creation of temporary table with primary key in ClickHouse 23.3+
-
#4072: add static
DataConnection.DefaultOnTraceConnectionproperty to set default application-wide trace handler -
#4079: fix
InvalidCastExceptiongenerated for some queries withSql.PropertyAPI - #4082: fix materialization of entity, queried using implemented interface, where interface has read-only property and entity class implements it with setter
-
#4086: fix multiple issues with
DataContext:-
#4057: async eager load operation on
DataContextcould fail with exceptionInvalidOperationException: There is already an open DataReader associated with this Connection which must be closed first. -
DataContextwithKeepConnectionAlive = falsesetting closes implicit eager load transaction after first query -
DataContextqueries caching doesn't work correctly (could affect only applications with multiple configurations for same database type)
-
#4057: async eager load operation on
Scaffold CLI
- #4061: Fix regression in association names generation for composite foreign keys
LinqToDB
-
#4037: fixed issue with incorrect use of connection string parameter by some of
[Oracle|PostgreSQL|SqlServer]ToolsAPIs
LinqToDB
-
#3966:
- prefer
field IN (subquery)SQL generation instead ofEXISTS(subquery with field filter)for scalar subqueries - improve
booleantype compatibility forClickHouseforOctonicaandMySqlproviders
- prefer
- #3997: don't throw exception from provider dialect detector when dialect already specified in context options and connection string is not set
-
#4001:
- added new extension point for query hints/extensions generation:
QueryExtensionScope.TableNameHint - [SQL Server] add temporal table extensions to filter by
FOR SYSTEM_TIMEclause:TemporalTableHint,TemporalTableAll,TemporalTableAsOf,TemporalTableFromTo,TemporalTableBetween,TemporalTableContainedIn
- added new extension point for query hints/extensions generation:
-
#4006: add
BigIntegertype support for PostgreSQL - #4010: fix potential issues with hint extensions
- #4011: fix nullability tracking for deep-nested optional associations
-
#4014: fix overloads conflict for
UsePostgreSQLconfiguration extensions -
#4015: add
WhereKeyOptimisticextension to apply query filter over primary key and lock field for specific record - #4016: disable unused left join optimization for joins with hints
- #4022: fix work with inherited attributes on properties
-
#4027: fix regression in
DataConnection.DefaultSettingsassignment handling
Scaffold CLI
-
#4021:
-
#945: add support for fluent metadata generation: new
--metadataoption with valuesnone,attributes(default),fluent - automatically pass generated mapping schema to context in generated context constructors (for fluent mapping and
PostgreSQLtuples mapping) - [PostgreSQL] fix error when scaffold includes
NpgsqlTypes.NpgsqlIntervaltype - [SQL CE] fix duplicate foreign key columns
- fixed equality generation for nullable
System.Data.SqlTypes.Sql*struct types andSqlHierarchyId - fixed equality generation for DB2 custom struct types (e.g.
DB2Int32) including nullable types - fixed defaults rendering in
--find-methodscommand help, addnoneoption to disable generation ofFind*methods
-
#945: add support for fluent metadata generation: new
Also check V5 migration notes.
LinqToDB
-
#3975: fix support for
AssociationSetterExpressionfor cases whenStorageuse different type compared to mapped association -
#3981: simplify and clarify
IMetadataReader.GetAttributesAPI contract:- remove use of generic arguments and set return type to
MappingAttribute[]fromT[] where T: MappingAttribute - document that implementation should return all mapping attributes for requested member/type
- remove use of generic arguments and set return type to
-
#3983: fix
InvalidCastExceptionfromInsertWithOutput*APIs when target and output types doesn't match -
#3986: fix
ContainstoINconversion for collections withnullvalues
LinqToDB
- #3959: fix issue with reverted default column order for mapping classes with inheritance. Thanks to Guillaume Lecomte for PR
-
#3961: add support for custom association setter expression, used on association load using
LoadWith/ThenWithAPIs (Thanks to Guillaume Lecomte for PR):AssociationAttribute.AssociationSetterExpressionMethodAssociationAttribute.AssociationSetterExpression
-
#3962: add additional overloads to
CreateTempTableAPI to support anonymous classes -
#3967: fixed incorrect equality operators implementations for
DataOptions -
#3969: (#1592, #1822) replace
MappingSchema.EntityDescriptorCreatedCallbackinstance delegate with- application-wide
MappingSchema.EntityDescriptorCreatedCallbackstatic delegate - context-specific delegate, set using
WithOnEntityDescriptorCreated/UseOnEntityDescriptorCreatedconfiguration extensions
- application-wide
-
#3970: add additional overloads to
Use<DB_NAME>options configuration extensions without connection string parameter
LinqToDB
-
#3643: added source table support to output/returning clause to Merge API:
-
MergeWithOutput[Async](SQL Server 2008+, Firebird 3.0+) -
MergeWithOutputInto[Async](SQL Server 2008+)
-
- #3840: fix type convert issues in mapping generation
-
#3858:
- improve detection of cases when we can generate single query with
APPLYinstead of multiple queries -
#3799: fix
NotImplementedExceptionfrom eager-load queries with single-record subqueries (e.g. usingFirstOrDefault)
- improve detection of cases when we can generate single query with
-
#3952: due to compatibility issues between
MySql.Dataprovider and recent versions onMariaDBwe drop support forMySql.Dataprovider use withMariaDB. You can still use it with oldMariaDBversions, but we don't accept issues for this provider/database combination and recommend to useMySqlConnectorprovider (forMySqltoo)
linq2db.AspNet
-
#3953: downgrade required
Microsoft.Extensions.DependencyInjectionandMicrosoft.Extensions.Logging.Abstractionsdependencies to version 6 from 7
LinqToDB
- #553: added API for record delete/update with optimistic lock. See notes below
-
#2690: add support for C# Nullable Reference Types annotations to infer nullability of columns and single-record associations. To enable it, set
Configuration.UseNullableTypesMetadata = true;option. Note that curently this is application-wide option and cannot be configured per-context - #3905: [MySql][MariaDB] added extensions to work with 'FOR UPDATE/SHARE' hints (see examples in tests)
-
#3900: performance-related optimizations and refactorings
- mapping attributes refactoring (see below)
- breaking changes to fluent mapping (see below)
- [BREAKING CHANGE]
Configuration.Linq.EnableAutoFluentMappingwas renamed toEnableContextSchemaEditto better reflect affected behavior and set it tofalseby default - [BREAKING CHANGE] disable support for mapping attributes from
System.ComponentModel.DataAnnotations.SchemaandSystem.Data.Linq.Mappingnamespaces by default - connection factory delegate accepts
DataOptionsinstance now (Func<DbConnection>->Func<DataOptions, DbConnection>). It allows user to access connection options, e.g. connection string:options => new SqlConnection(options.ConnectionOptions.ConnectionString) - [BREAKING CHANGE] custom
IMetadataReaderimplementations should support requests for base attribute types. See more details here
-
#3906: fixed
InvalidOperationExceptionin eager load -
#3910: fixed C# NRT annotations on
LoadWith/ThenLoadAPIs -
#3921: fixed several issues with asociations:
-
#3658: respect
CanBeNullfor associations with custom predicate expression - prevent "unused" inner join removal by sql optimizer if it was added by association
- fix generation of joins for associations for
Countscalar queries
-
#3658: respect
- #3926: fixed issue in eager load
- #3933: fix context mapping schema pollution in temporary table APIs with custom entity configuration delegate parameter
-
#3939: add new connection extensions to simplify database connection setup without need to define interceptor class:
UseBeforeConnectionOpened/UseAfterConnectionOpened. Both extensions accept sync delegate with connection instance parameter and optional async delegate for use from async code if you need to call blocking code from setup delegate. Some examples where it could be useful:- Sql Server connection authentication setup using
SqlCredentialorAccessToken - SQLite database encryption setup using
PRAGMA *KEYdirectives
- Sql Server connection authentication setup using
-
#3943: improve performance of
System.Data.Linq.Binary.NET Core compatibility class. Thanks to Guillaume Lecomte for PR
Scaffold CLI
- #3728: fix one-to-one association name generation regression
-
#3896: fix
PE image doesn't contain managed metadata.error when use T4 template for interceptors (thanks to @AndyBan for PR) -
#3938: fix SQL Server support regression in
preview-1
Namespace: LinqToDB.Concurrency.
There are two new extensions to leverage record update and delete operations using optimistic locks:
UpdateOptimistic[Async]DeleteOptimistic[Async]
Those extensions:
- accept record object you need to update or delete with version field value set and add version check to your query;
- return number of affected records which you should check to see if operation executed successfully or nothing was updated/deleted due to version change in database or because record is not found.
To use those extensions you need to tell Linq To DB which field should be used as version field and how to generate new version value on optimistic update. For that you can:
- annotate it with
OptimisticLockPropertyAttributewhich provides several standard version generation strategies; - implement your own one using
OptimisticLockPropertyBaseAttributeas base attribute class and specify update expression inGetNextValuemethod.
Built-in strategies:
-
VersionBehavior.Auto: use database-generated value. E.g. SQL Serverrowversionfield type orUPDATE TRIGGER -
VersionBehavior.AutoIncrement: use autoincrement strategy (by +1) on numeric field -
VersionBehavior.Guid: useGuid.NewGuid()client side generation. Could be applied to fields ofGuid,string(usingguid.ToString()) orbyte[](usingguid.ToByteArray()) types
Example:
[Table]
public class MyTable
{
[PrimaryKey, Identity]
public int Id { get;set; }
[Column]
[OptimisticLockProperty(VersionBehavior.Guid)]
public Guid Version { get;set; }
[Column]
public string Name { get;set; }
// ... other fields
}
using var db = new MyContext();
var record1 = new MyTable()
{
// initial version
Version = Guid.NewGuid(),
Name = "My Name"
};
// add record to database
db.Insert(record1);
record.Name = "New Name";
if (db.UpdateOptimistic(record1) == 0)
{
// update failed - sombody managed to remove our record or change it's version
throw new InvalidOperationException(
$"Update failed, record with id={record1.Id} and"
+ $" version={record1.Version} wasn't found in database");
}
else
{
// add additional condition to query
if (db.GetTable<MyTable>().Where(r => r.Name.Contains("My")).DeleteOptimistic(record1) == 0)
{
// use only primary key + version as delete condition
if (db.DeleteOptimistic(record1) == 0)
{
throw new InvalidOperationException(
$"Delete failed, record with id={record1.Id} and"
+ $" version={record1.Version} wasn't found in database");
}
}
}This release introduce major refactoring to mapping attributes which includes:
- all mapping attributes now inherited from
MappingAttributebase class, which means all of them now havestring? Configurationproperty to specify configuration-specific mapping. Previously it wasn't possible to specify configuration-specific mappings using some mapping attributes; -
interface IMetadataReadernow has generic constrainTAttribute: MappingAttributewhich will require changes from you, if you use custom metadata readers- you need to add generic constrains to your implementation
- you cannot return non-mapping attributes from reader (which already was useless, as
linq2dbdoesn't query such attributes from readers anyways)
- attribute getter methods in
MappingSchemaclass now also haveTAttribute: MappingAttributeconstrain now. This shouldn't affect most of users as those methods designed for use bylinq2dbitself
With this release we introduce breaking change to fluent mapping configuration, which will require changes from all users of fluent mapping.
Previously to configure mappings using fluent builder all you need to do is to create builder using GetFluentMappingBuilder() method on mapping schema or database context and add mappings using builder method which immediatly reflected in mapping schema.
We change this behavior to postpone configured mappings registration in mapping schema till explicit call to new Build() method on fluent mappings builder and remove GetFluentMappingBuilder from MappingSchema and DataContext and DataConnection classes to make this breaking change explicit.
E.g. you have following code which worked before:
// create new data context
using var db = new MyDataContext();
// create new mapping schema for fluent mappings
// and add it to context
var fluentMappings = new MappingSchema();
db.AddMappingSchema(fluentMappings);
// get mappings builder from mapping schema
var builder = fluentMappings.GetFluentMappingBuilder();
// or using context mapping schema directly
// var builder = db.MappingSchema.GetFluentMappingBuilder();
// or
// var builder = db.GetFluentMappingBuilder();
// configure mappings
builder.Entity<MyEntity>().Property(e => e.Id).IsPrimaryKey();
// all done, you can use your mappings already
// delete entity by primary key value from Id property
db.Delete(entity);While it worked before, that example contains a lot of issues with performance and will not work in new version for at least two reasons:
- there is no
Build()method call yet, so context don't know anything about new mappings; -
AddMappingSchema(..)method called before mappings configured - this will also not work anymore, because fluent mappings not set to mapping schema yet byBuild()call; - if you used
GetFluentMappingBuildermethod on context/context schema - it will also will not work as we changed library defaults and context mapping schema is not editable by default anymore.
Except those obvious breaking changes this example also has big performance issue: if you need to configure mappings you need to do it once and then use pre-configured mapping schema with all context instances otherwise you will have big performance penalty as linq2db will be unable to reuse cached mapping information.
Proper configuration of (fluent) mappings:
// setup mappings once, e.g. in application startup or MyDataContext static constructor:
private readonly MappingSchema _mappings;
static MyDataContext()
{
// create shared mapping schema instance with all context mappings
_mappings = new MappingSchema();
// configure fluent mappings
// create builder instance explicitly
new FluentMappingBuilder(_mappings)
.Entity<MyEntity>()
.Property(e => e.Id)
.IsPrimaryKey()
// (!) commit mappings to mapping schema
Build();
// also we can configure additional mappings
_mappings.SetConvertExpression(...);
}
// pass mapping schema to context base contructor (e.g. using DataOptions)
public MyDataContext(DataOptions options)
: base(options.UseMappingSchema(_mappings))
{
}We are changing some library defaults to provide better performance by default. It could break some users.
Data context mapping schema (MappingSchema IDataContext.MappingSchema property) from now is read-only by default.
It means you cannot edit it from context instance:
var db = new MyContext();
// add fluent mappings to context mapping schema
db.MappingSchema.GetFluentMappingBuilder();
// register new type conversion
db.MappingSchema.SetConvertExpression(...);You can restore old behavior using following code:
// application-wide switch
Configuration.Linq.EnableContextSchemaEdit = true;
// context-wide option
var db = new MyContext(new DataOptions().UseEnableContextSchemaEdit(true));But we wont recommend doing it as it will affect performance. Recommended approach is to create single mapping schema instance, configure it and use with all context instances. You can see example how to do it in fluent mappings section.
In previous releases Linq To DB was able to consume some mapping attributes from System.ComponentModel.DataAnnotations.Schema and System.Data.Linq.Mapping namespaces.
Starting from this release support for those attributes is not enabled by default. Those mappings were used by minor part of users but calls to corresponding metadata providers are done for all users.
If you used them, you need to enable corresponding metadata readers:
// for System.Data.Linq.Mapping support
var reader = SystemDataLinqAttributeReader();
// for System.ComponentModel.DataAnnotations.Schema
var reader = SystemComponentModelDataAnnotationsSchemaAttributeReader();
// enable globally
MappingSchema.Default.AddMetadataReader(reader);
// enable for specific mapping schema (don't forget to setup
// schema once per-application to benefit from mappings caching)
mappingSchema.AddMetadataReader(reader);Obsoletion note: in final release we removed generics from GetAttributes and require from them to return all attributes always
If you implemented custom metadata reader in your application (interface IMetadataReader), you will need to make several changes to your implementation:
- add
where T : MappingAttributegeneric constrain toGetAttributesmethods implementation - change
GetAttributeslogic to support calls whereT = MappingAttribute
From this release linq2db could call GetAttributes methods using base attribute type instead of concrete type. E.g. GetAttributes<MappingAttribute> instead of GetAttributes<TableAttribute>. To support this new behavior you will need to make two changes to your implementation.
Replace T check conditions to use IsAssignableFrom:
// old code
if (typeof(T) == typeof(TableAttribute))
{
// create and return TableAttribute instance
}
// new check. takes inheritance into account
if (typeof(T).IsAssignableFrom(typeof(TableAttribute)))
{
// create and return TableAttribute instance
}Return all applicable attributes if all of them derived from T:
// old code
if (typeof(T) == typeof(ColumnAttribute))
{
// create and return ColumnAttribute instance
}
else if (typeof(T) == typeof(Sql.ExpressionAttribute))
{
// create and return Sql.ExpressionAttribute instance
}
// new code
// because T could represent base class, both supported attributes should be returned
var result = new List<T>();
if (typeof(T).IsAssignableFrom(typeof(ColumnAttribute)))
{
// create ColumnAttribute instance
result.Add(columnAttr);
}
if (typeof(T).IsAssignableFrom(typeof(Sql.ExpressionAttribute)))
{
// create Sql.ExpressionAttribute instance
result.Add(expressionAttr);
}
// return all applicable attributes
return result.ToArray();-
#3530:
-
#471: fix issue when changing some application-wide options form
Configuration.Linqcould affect existing connections/cached queries, see more details below on options rework - #472: introduced connection-wide provider specific options instead of existing application-wide options
- add
void RemoveInterceptor(IInterceptor interceptor)method to contexts - add
DataConnection.OnRemoveInterceptorevent - improved SQL dialect detection logic for SQL Server, PostgreSQL and Oracle to cache detection results per-connection string
- context options
DataOptionsinstance accessible usingIDataContext.Optionsproperty - [T4] added new T4 setting
string GetDataOptionsMethodto specify name of custom static method withDataOptionsreturn type, called by generated constructors - [t4] renamed T4 option
GenerateLinqToDBConnectionOptionsConstructorstoGenerateDataOptionsConstructors - [SQL Server] default SQL Server dialect bumped to SQL Server 2012 from 2008
- added support for automatic detection of SQL Server provider (
SqlServerProvider.AutoDetect)
-
#471: fix issue when changing some application-wide options form
- #3898: removed obsoleted APIs
- #3902: [Sybase] fix issue with too long parameter name trimming
AutoDetect logic enabled by default for SQL Server, PostgreSQL and Oracle providers if user doesn't specify required dialect version explicitly:
- SQL Server provider will use
AutoDetectlogic to detect SQL dialect instread ofSQL Server 2008(2012starting from this release) dialect by default. To disable it setSqlServerTools.AutoDetectProvidertofalse - PostgreSQL provider will use
AutoDetectlogic to detect SQL dialect instread ofPostgreSQL 9.2dialect by default. To disable it setPostgreSQLTools.AutoDetectProvidertofalse - Oracle provider will use
AutoDetectlogic to detect SQL dialect instread ofOracle 12dialect by default. To disable it setOracleTools.AutoDetectProvidertofalse
This PR introduce major options overhaul.
LinqToDBConnectionOptionsBuilder options builder class alongside with LinqToDBConnectionOptions and LinqToDBConnectionOptions<T> classes
replaced with DataOptions[<T>] classes. This will require from you to change configuration logic a bit:
// OLD CONFIGURATION APPROACH
// 1. create options builder
var optionsBuilder = new LinqToDBConnectionOptionsBuilder();
// 2. set options to builder
optionsBuilder.UseSqlServer(connectionString);
// 3. generate options object using Build() method and pass it to context or register in DI container
new DataContext(optionsBuilder.Build());
// NEW CONFIGURATION APPROACH
// 1. create immutable options object
var options = new DataOptions();
// 2. "mutate" it using same configuration methods as before
// IMPORTANT: because options object is immutable you should chaing configuration methods calls
// or save returned options object to variable
options = options.UseSqlServer(connectionString);
// 3. pass options to context/DI container
new DataContext(options);As you can notice main changes are:
- two old configuration classes (builder and options) replaced with single options class
- because options are immutable (compared to old builder), you must not forget to use results of
Use*configuration methods - configuration build extensions not changed in general, several old extensions that were not used
Use*naming pattern were renamed. See full list of renames below -
AspNetconfiguration extensionsAddLinqToDB`AddLinqToDBContextnow require that you return options instance fromconfigure` delegate parameter
Changes to application-wide configuration options (see list of options below) doesn't affect already created contexts and cached queries
Configuration.Linq.PreloadGroupsConfiguration.Linq.IgnoreEmptyUpdateConfiguration.Linq.GenerateExpressionTestConfiguration.Linq.TraceMapperExpressionConfiguration.Linq.DoNotClearOrderBysConfiguration.Linq.OptimizeJoinsConfiguration.Linq.CompareNullsAsValuesConfiguration.Linq.GuardGroupingConfiguration.Linq.DisableQueryCacheConfiguration.Linq.CacheSlidingExpirationConfiguration.Linq.PreferApplyConfiguration.Linq.KeepDistinctOrderedConfiguration.Linq.ParameterizeTakeSkipConfiguration.Linq.EnableAutoFluentMapping
Same logic applied to retry policy objects and application-wide options for them:
Configuration.RetryPolicy.DefaultRandomFactorConfiguration.RetryPolicy.DefaultExponentialBaseConfiguration.RetryPolicy.DefaultCoefficient
Also all those options now could be configured per-context using Use<OptionName> configuration extensions.
For Configuration.Linq options:
UsePreloadGroupsUseIgnoreEmptyUpdateUseGenerateExpressionTestUseTraceMapperExpressionUseDoNotClearOrderBysUseOptimizeJoinsUseCompareNullsAsValuesUseGuardGroupingUseDisableQueryCacheUseCacheSlidingExpirationUsePreferApplyUseKeepDistinctOrderedUseParameterizeTakeSkipUseEnableAutoFluentMapping
For Configuration.RetryPolicy options:
UseRetryPolicyUseDefaultRetryPolicyFactoryUseFactoryUseMaxRetryCountUseMaxDelayUseRandomFactorUseExponentialBaseUseCoefficient
Added UseBulkCopy<option_name>() helpers to configure connection-wide bulk copy defaults.
Also for following option objects we added With<option_name> configuration extensions:
BulkCopyOptionsRetryPolicyOptionsQueryTraceOptionsConnectionOptionsLinqOptions
Introduced support for provider-specific options instead of application-wide settings, usually located in <DB>Tools provider classes.
Current release contains options for all providers (see list below). They could be configured globally using <DB>Options.Default options set or using Use<DB> configuration extension.
List of available options (old options were marked with Obsolete attribute):
- [ALL]
<DB>Tools.DefaultBulkCopyType-><DB>Options.BulkCopyType - [MSSQL]
SqlServerConfiguration.GenerateScopeIdentity->SqlServerOptions.GenerateScopeIdentity - [SQL CE]
SqlCeConfiguration.InlineFunctionParameters->SqlCeOptions.InlineFunctionParameters - [SQLite]
SQLiteTools.AlwaysCheckDbNull->SQLiteOptions.AlwaysCheckDbNull - [PostgreSQL]
PostgreSQLTools.NormalizeTimestampData->PostgreSQLOptions.NormalizeTimestampData - [PostgreSQL]
PostgreSQLSqlBuilder.IdentifierQuoteMode->PostgreSQLOptions.IdentifierQuoteMode - [Oracle]
OracleTools.DontEscapeLowercaseIdentifiers->OracleOptions.DontEscapeLowercaseIdentifiers - [Informix]
InformixConfiguration.ExplicitFractionalSecondsSeparator->InformixOptions.ExplicitFractionalSecondsSeparator - [Firebird]
FirebirdConfiguration.IdentifierQuoteMode->FirebirdOptions.IdentifierQuoteMode - [Firebird]
FirebirdConfiguration.IsLiteralEncodingSupported->FirebirdOptions.IsLiteralEncodingSupported - [DB2]
DB2SqlBuilderBase.IdentifierQuoteMode->DB2Options.IdentifierQuoteMode - [ClickHouse]
ClickHouseConfiguration.UseStandardCompatibleAggregates->ClickHouseOptions.UseStandardCompatibleAggregates
T4 templates updated to:
- generate new options constructors
- added new T4 setting
string GetDataOptionsMethodto specify name of custom static method withDataOptionsreturn type, called by generated constructors - renamed T4 option
GenerateLinqToDBConnectionOptionsConstructorstoGenerateDataOptionsConstructors
-
BulkCopyOptionchanged fromclasstoclass record. Because class records are immutable, you should usewithstatement or newWith<BulkOption>()helpers - added
DataConnectionconstructors withFunc<DataOptions,DataOptions> optionsSetterparameter to build options usingDataConnection.DefaultDataOptionsas input - method rename:
UseAccessODBC->UseAccessOdbc - method rename:
WithInterceptor->UseInterceptor - method rename:
WithTracing->UseTracing - method rename:
WithTraceLevel->UseTraceLevel - method rename:
WriteTraceWith->UseTraceWith - property rename:
SqlServerTools.Provider->SqlServerTools.DefaultProvider - property rename:
GrpcDataContext.Options->GrpcDataContext.ChannelOptions - internal infrastructure support class
TypeExtensionswithTypeextension methods (UnwrapNullableType,IsNullableType,IsInteger,IsNumericType,IsSignedInteger,IsSignedType) removed from public surface - added
OracleVersion.AutoDetect,PostgreSQLVersion.AutoDetect,SqlServerVersion.AutoDetectenum values to explicitly specify that SQL dialect should be detected byLinqToDBbased on server version -
LinqToDB.Common.Internal.ValueComparer[<T>]classes removed from public surface
-
#3946:
- [DB2][Firebird][Oracle] remove unnecessary wrapper subquery around
SELECTwithCTEforINSERT FROM SELECTqueries - [DB2] fixed position of
CTEclause inINSERT FROM SELECTqueries - #3945: fixed generation of addtional unnecessary columns in select sub-query with composite columns
- [PostgreSQL][Firebird][MySql][MariaDb] don't add
RECURSIVEkeyword to simpleCTEclauses, defined byGetCteAPI
- [DB2][Firebird][Oracle] remove unnecessary wrapper subquery around
- #3218: [T4][SQLite] fixed issue with schema load where it could fail due to outdated sqlite runtime version used
-
#3579: corrected nullability annotations on
Sql.Collatefunction -
#3712: add
InsertWithOutputextensions forIValueInsertableinterface - #3751: treat non-nullable columns from left joins as nullable during SQL generation
-
#3760, #3834: fixed issue where
InsertWithOutputAPI cannot handle columns when column's name and property's name are different -
#3761: improve mapping of
Nullable<T>.GetValueOrDefault()to generate query parameter - #3762: [Scaffold] fix SQL Server scalar function mappings to always include schema name as required by SQL Server
- #3777: [Scaffold] fixed issue where scaffold could generate classes/properties in different order between generations. From now generated code will have mappings for tables and functions ordered by name in database and columns by column ordinal
-
#3788, #3872: improve
GroupBy(constant)optimization to exclude unnecessaryGROUP BYgeneration -
#3791: fix
InvalidOperationException: No coercion operator is defined...error when custom conversion specified between types withTypeConvertersupport -
#3797: [ClickHouse] enable support for
EXCEPT ALL/INTERCEPT ALLset operators -
#3803: Scaffold framework improvements:
- add
AfterSourceCodeGenerated(FinalDataModel model)interceptor to provide access to data model used for code generation with actual indentifiers, used for generated code, set - add
string? ForeignKeyNameproperty toAssociationModelclass
- add
- #3809: fix issue in conditional expressions handling for associated tables
- #3810: [Scaffold] fixed composite foreign key association generation to use all key columns instead of first key column only
-
#3811: Fix equality implementation for
System.Data.Linq.Binarytype for .net (core) runtimes -
#3820: [Scaffold] add native support for
net6.0andnet7.0to scaffold cli tool -
#3825: Fixed support for some mapping attributes in fluent mapping (
MapValueAttributeand some more) -
#3826: Improve error message for
CREATE TABLEcommand when column database type cannot be determined automatically to include column member's .NET type name -
#3829: [ClickHouse] add support for
ClickHouseDecimaltype fromClickHouse.Clientprovider -
#3837: [Informix] Improve SQL generation for
Nvlfunction -
#3843: expose constructor of
DataReaderWrapperclass to unblock customDataReaderextensions implementation -
#3854: [SQL Server] temporal tables support in schema/scaffold:
- mark from/to validity range columns as read-only
- mark temporal history table as read-only
- add option to ignore history tables on schema load (
mssql-ignore-temporal-history-tablesflag inlinq2db.cliandGetSchemaOptions.IgnoreSystemHistoryTablesin schema API)
-
#3855: implement
IAsyncDisposableonDataContextTransaction -
#3863: disposal of transaction without explicit call to
Rollbackmethod will not callRollbackexplicitly on transaction object anymore (transaction still be rolled back by database provider if needed)-
BREAKING such transactions will not generate
RollbackTransactiontrace event anymore. Also we introduce newDisposeTransactiontrace event as replacement
-
BREAKING such transactions will not generate
-
#3865: fixed
ValueConvertersupport in remote context
-
#3462: support single query generation for queries with multiple
cross applyclauses -
#3759:
- Update SQL Server 2022 support to RC.0 level (
charsparameter support forstring.TrimEnd(string value, char[] chars)andstring.TrimStart(string value, char[] chars)mappings) - add
charsparameter support forstring.TrimEnd(string value, char[] chars)andstring.TrimStart(string value, char[] chars)mappings for following databases:- SQLite
- SAP HANA
- PostgreSQL
- Oracle
- Informix
- DB2
- ClickHouse
- SQL Server 2022
- Update SQL Server 2022 support to RC.0 level (
-
#3774: fix 4.2.0 regression with handling of
INclauses in columns
-
#1796: new
ClickHousedatabase provider. See details below -
#3584: [PostgreSQL] Add
MERGEqueries support toPostgreSQLprovider (requires PostgreSQL 15) -
#3595: Add new command interceptor events
BeforeReaderDisposeandBeforeReaderDisposeAsyncinvoked beforeDbDataReaderdisposal -
#3649: [PostgreSQL][SQLite] Improve
UPDATE ... FROMqueries support for PostgreSQL and SQLite -
#3659: [SQL Server] Add initial support for SQL Server 2022:
- new dialect
SqlServerVersion.v2022 - support for INGORE NULLS qualifier for FIRST_VALUE/LAST_VALUE window functions (requires CTP 2.0)
- support for IS [NOT] DISTINCT FROM operator (requires CTP 2.1)
- new dialect
-
#3664: Fix parameters caching in
LoadWithfilters -
#3667: Fix compatibility with
Npgsql7 -
#3668: Fixed
An item with the same key has already been addederror forGroupByqueries with eager load inroduced by 4.1.1 release - #3669: Fix duplicate columns detection for columns with conditional expressions
-
#3673: [Scaffold CLI] added new schema option to specify default database schema(s) explicitly (
default-schemas: string[]) -
#3676: [Scaffold CLI] fixed
transformationoption support from command line orjsonconfig-
nonevalue is recognized - help mentions proper name for
associationvalue (instead of non-existingt4)
-
-
#3679: [Scaffold] Add by-name filtering options for stored procedures, scalar and aggregate functions (table functions already covered):
-
include-stored-procedures/exclude-stored-procedures -
include-scalar-functions/exclude-scalar-functions -
include-aggregate-functions/exclude-aggregate-functions
-
-
#3683:
- made changes to
Linq To DBto support databases without transactions (e.g.ClickHouse) - added
TransientRetryPolicyandDbExceptionTransientExceptionDetectorclasses to support new propertyDbException.IsTransientby retry policy mechanism. Available fornet6.0tfm
- made changes to
-
#3684: fix
Argument types do not matchexception whenValueConverterwithHandlesNulls = trueoption used -
#3685: fix
nullvalues handling in enumerable sources to generateNULL aliasinstead ofNULLalias, which could lead to sql errors for some databases -
#3687: fix argument nullability tracking for
CASTand some other functions to avoid null checks generation for non-nullable arguments -
#3689: Fix date/time strings generation i queries to generate fixed-length components (e.g.
01:05for time instead of1:5) -
#3690:
- obsolete
SqlDataType.GetDataTypemethod (MappingSchema.GetDataTypeshould be used) -
[BREAKING]: Conversion functions that doesn't specify exact type (
System.Convert.ToDecimal,LinqToDB.Common.Convert) change behavior for decimal type. They will generate cast to decimal type definition, specified in mapping schema (usuallydecimalwithout precision and scale set). Previously they used hardcodeddecimal(29, 10)type.- Workarounds:
- register suitable decimal type mapping in mapping schema (not recommended):
mappingSchema.AddScalarType(typeof(decimal), new SqlDataType(new DbDataType(typeof(decimal), DataType.Decimal, null, null, <precision>, <scale>))); - use better-typed convert API, e.g.
Sql.Convert(Sql.Types.Decimal(<precision>,<scale>), convertedValue)
- register suitable decimal type mapping in mapping schema (not recommended):
- List of affected providers:
- DB2:
decimal(29, 10)->decimal - Firebird:
decimal(18, 10)->decimal - SQL Sever CE:
decimal(29, 10)->decimal - SQL Sever:
decimal(29, 10)->decimal - MySQL/MariaDB:
decimal(29, 10)->decimal - SAP/Sybase ASE:
decimal(29, 10)->decimal - Oracle:
decimal(29, 10)->decimal
- DB2:
- Workarounds:
- obsolete
-
#3697: Fix issue when
UpdateWithOutputcould generateNULLinstead of column in outputs for complex queries -
#3701: add support for sequence name configuration for column using fluent mapping (
UseSequenceorHasAttribute(SequenceNameAttribute)methods) -
#3703: [PostgreSQL] add support for
NpgsqlIntervaltype fromNpgsql6 -
#3705:
- [PostgreSQL] add type hint to
byteaanduuidliterals (::bytea,::uuid) - [PostgreSQL] add new SQL dialect
PostgreSQLVersion.v15. EnablesMERGEquery generation forInsertOrReplace/UpdateAPIs
- [PostgreSQL] add type hint to
-
#3709: [CLI] fix
ColumnType not provided by schema for tableerror forAccessscaffolding usingODBCprovider fordecimalcolumns - #3728: [Scaffold] Fix generation of association name for one-to-one relation over primary keys in CLI tool
-
#3729: fix
Mergeinto table with query filters defined -
#3731: [Oracle] reset
ArrayBindCountproperty onOracleCommandto prevent exception on command reuse afterBulkCopyinAlternativeBulkCopy.InsertIntomode - #3738: remove incorrect database type inferring logic for binary expressions
-
#3747: [Scaffold] CLI tool improvements
- tolerate allow trailing commas in JSON config
- properly detect and report conflicting options in JSON config
This release adds initial support for ClickHouse database.
Following providers/protocols supported:
- MySQL interface using MySqlConnector
- HTTP(S) interface using ClickHouse.Client
- TCP (binary) interface using Octonica.ClickHouseClient
To see supported data type mappings and related issues with providers see this document.
- added new bulk copy options
BulkCopyOptions.MaxDegreeOfParallelismandBulkCopyOptions.WithoutSessionforClickHouse.ClientHTTP provider - CLI scaffold: implemented
- T4 scaffold: not planned
- query parameters: not supported/not planned
- LinqPAD support: will be added in future releases
- Custom query hints/extensions: will be added in future releases (feedback on which extensions needed is welcome)
-
#3629: fix
OUTPUT/RETURNINGinto temporary table - #3630: [SQL Server] fix type load exception for self-extracting applications
-
#3633: fix
AddLinqToDBContextDI helper to support context constructors with additional parameters -
#3636: fix
GROUP BYquery caching -
#3637: improve typing of
CASEexpression
- #861: fix tracing for misconfigured/failed connection
-
#3557: Fix cases where optional association could produce
INNER JOINinstead ofLEFT JOIN -
#3585: [Oracle] Add support for
Devart.Data.Oracleprovider- #3610: fix scaffolding exception with Oracle 19+
-
#3591: fix exception from
DataContext.ctor(IDataProvider, string)contructor -
#3594: Improve typing of
COALESCE -
#3596: [SQL Server] Add
OPENJSONfunction mapping (LinqToDB.DataProvider.SqlServer.SqlFn.OpenJson(...)) -
#3601: [Oracle] Specify
DataType.Cursorforref cursorcolumns in scaffold -
#3604: [Scaffold] Fixed include/exclude object filter parsing when both
schemaandname/regexfilters specified -
#3611: [MySQL] Support
ColumnAttribute.Lengthvalues in [256, 65535] range forVarChartype forCreateTableAPIs -
#3612: [Scaffold] Fix exception from
help scaffoldcommand from some environments - #3615: [Scaffold] Update naming options configuration approach. Now you don't need to specify all naming option properties from scratch if you want to change only one property (e.g. name casing) - values for unspecified properties will be taken from default option value
-
#1878: fix
Guidcompatibility issue withMicrosoft.Data.SQLite3+. Now it is possible to mapGuidto text by usingColumn(DbType="TEXT")orColumn(DataType=DataType.ONE_OF_TEXT_TYPES_HERE). DefaultGuidmapping is still remainsbinary -
#3563: add missing dependencies to
linq2db.PostgreSQLT4 nuget - #3564: fixed issues with pre-generated scaffolding template (missing namespace and NRT warnings). Thanks to Alexey Zagoskin for fixing it
- #3567: improve scaffold tool help to include default switch values for T4 compat mode
- #3568: fixed names of generated files by scaffold tool to have same name as generated class even after class renamed by scaffold interceptor
-
#3569: add new switch
--generated-suffixto scaffold tool to add.generatedsuffix to generated file names -
#3570: [SQL Server] fixed handling of date/time types (
DateTime,DateTimeOffset,TimeSpan,DateOnly,SqlDateTime) to respect precision and generate typed literals in queries -
#3575: fixed
linq2db.AspNetnuget to reference proper version ofMicrosoft.Extensions.DependencyInjection -
#3578: [CLI] removed database name from name of table/view/procedure, returned by schema by default. Use new option
--database-in-nameto re-enable it
No changes since RC2.
-
#3502:
DateOnlytype support (all databases) -
#3506: fix missing
Nullable<T>.Valuehandling in some places -
#3534: Scaffold tool improvements
- adds extension points to customize generated entities, procedures, functions and associations
- adds
--equatable-entitiesoption to implement functionality ofEquatable.ttincludeT4 template in scaffold tool (generation ofIEquality<T>interface implementation on entity classes)
-
#3536: add support for database packages
- add new
Packageproperty inSql.TableFunctionAttribute - automatically wrap table function call in
TABLE(...)wrapper forDB2 LUWandOracle 11dialects - [Oracle][Firebird][DB2] add support for functions and packages to Schema API
- add support for package procedures and functions to scaffold by
T4andlinq2db.cli
- add new
-
#3541: improve value nullability tracking, annotate functions in
Sqlclass for nullability where it was missing -
#3542: fix support for members, marked with
Sql.ExpressionAttribute, in association queries -
#3543: fix rare
IndexOutOfRangeExceptionin queries with functions -
#3547: add
Sql.NullIffunction, mapped toNULLIFsql function (with emulation for databases which doesn't support it) -
#3548: fixed regression in
PostgreSQLenum parameters support
Database package is a named group of procedures and functions (plus types and variables in some DB), supported by following databases:
- Oracle Database
- DB2 LUW (under
modulename) - Firebird 3+
- SAP HANA (under
libraryname) - MariaDB
By support of packages in Linq To DB we mean following:
- support of package table functions mapping using
Sql.TableFunctionAttributeby addingSql.TableFunctionAttribute.Packageproperty to specify package name for function - support of package functions and procedures in
Schema API - support for package functions and procedures in database scaffolding (using both
T4templates andlinq2db.cliutility)
Known issues and limitations:
- [MariaDB] package stored procedures cannot be called using stored procedure API (
QueryProc,ExecuteProc) withMySql.Dataprovider (provider bug). User should use raw sql calls likeCALL package.proc(...)or even better - switch toMySqlConnectorprovider - [SAP HANA] library functions/procedures cannot be called using native unmanaged provider due to provider bug.
ODBCprovider should be used - [SAP HANA][MariaDB] packages not supported by Schema API (and scaffolding) because those databases don't expose required metadata
Also contains all changes from Release 3.7.0.
For migration notes check this document.
-
#2452: Query Extensions API to extend queries with custom SQL at specific points. See details below.
- [SQL Server] adds new SQL Server dialect levels:
SqlServerVersion.v2014andSqlServerVersion.v2019enum values andProviderName.SqlServer2019identifier - improved SQL optimization to remove unnecessary nesting for SQL like
SELECT * FROM (sub-query)
- [SQL Server] adds new SQL Server dialect levels:
- #2582: Improved handling of changes to mapping schema to avoid issues when changes ignored due to cached queries
-
#2619: Improved support for set (
UNION-like) queries with sorting -
#3097: Default value for
Configuration.ContinueOnCapturedContextsetting changed tofalse(as it should be) - #3098: New database scaffold dotnet tool implemented to replace old T4 templates. See more details below
- #3410: Remote context refactoring. See more details below
-
#3411: [SQL Server] Added pre-generated mappings for
sysandINFORMATION_SCHEMAschemas for SQL Server:-
LinqToDB.DataProvider.SqlServer.SqlType: type name generators -
LinqToDB.DataProvider.SqlServer.SqlFn: functions and variables -
LinqToDB.Tools.DataProvider.SqlServer.Schemas.SystemDB(linq2db.Toolsnuget package): system schemas data context
-
-
#3441: Removed
netcoreapp2.1TFM. Linq To DB still available for .NET Core 2.1 usingnetstandard2.0TFM. -
#3496: [Breaking]
DataConnection.GetTableinstance methods removed as they duplicate existing data context extension methods - #3499: Enable CTE support for SQL Server 2005 dialect
-
#3502:due to packaging error, feature will be shipped in RC2DateOnlytype support (all databases) -
#3508: Support
IReadOnlyDictionary.ContainsKeymethod in queries -
#3514: fixed SQL generation for
[NOT] IN (...)operator inCompareNullsAsValues = truemode to use value semantics fornull -
#3515: [Breaking]
Sql.<type_name>database type name generation properties moved toSql.Types."namespace" to avoid naming conflicts withusing static Sqlcode - [BREAKING] Default SQL Server provider changed from
System.Data.SqlClienttoMicrosoft.Data.SqlClient(you can useSqlServerTools.Providerproperty to change it back) - [BREAKING] We are marking most of database provider classes (e.g.
SqlServerDataProvider) as abstract. There are many reasons why you shouldn't create provider instance manually. Proper way to get provider instance is to use<dbname>Tools.GetDataProvider(...)method orDataConnection.GetDataProvider(...)methods. Only situation when you should create provider instance manually is when you sub-class provider to override some of it's methods. And even is such case it is better to register your provider implementation inDataConnectionwithAddDataProvidermethod.
With this release we obsolete some code:
- several properties on
AssociationAttribute(KeyName,BackReferenceName,IsBackReference,Relationship) andRelationshipenum. It was never used byLinq To DB. T4 templates and scaffolding tool will not generate them anymore. -
DataConnection.OnTraceproperty.LinqToDBConnectionOptions.OnTraceshould be used instead
For detailed documentation check tool nuget readme.
For feedback please use this discussion.
With RC1 we release initial version of new database scaffolding tool, which will replace T4 templates.
We still plan to ship T4 templates for Linq To DB 4 but there is no plans to introduce new T4 features and we plan to obsolete them completely in future (Linq To DB 5 probably?).
T4 templates were introduced in times when Visual Studio and .NET Framework were only development platforms and doesn't reflect current situation on .NET world anymore:
- Visual Studio not available for non-Windows platforms and other IDEs lack support for T4 preprocessing features, required for them to work (e.g. MS Build directives support)
- Visual Studio runs T4 templates using .NET Framework as host (x86 for VS 2017- and x64 process for VS 2022). Other IDEs could use .NET Core runtime for T4 templates. This creates two usability issues:
- T4 templates use .NET Framework versions of database providers which will not work in .NET Core hosts
- some database providers use unmanaged code and require specific process architecture, but Visual Studio doesn't give users such choice
Those are main issues, that cannot be solved with current T4 templates architecture.
Current release (4.0.0-rc.1) ships base scaffolding functionality and initial support for scaffolding process customization. Currently customization includes hooks for database schema load process. Later releases will add remaining hooks.
List of additional changes:
- new implementation has full control over generated code which allows it to generate valid code where T4 templates could fail:
- automatic detection and fix of naming conflicts within generated code including method overloads handling and support for conflicting names from external code (requires from user to provide list of conflicting identifiers). E.g. see T4 issues #1586, #2168
- proper literals generation (e.g. escaping of characters in generated strings)
- language-agnostic model allows generation of data model code in different laanguages/language versions (current release ships only C# support, but at least we plan to introduce F# support in future)
- #1825: file-per-class code generation support
-
#1897: new option to enable/disable
@returnparameter scaffolding for SQL Server stored procedures -
#2793: new options to generate various entity
FindandFinqQueryextension methods including async versions ofFindmethod - [Access] support for mixed scaffold mode, which use two database providers to load database schema:
OLE DBandODBCproviders. This feature is needed, because bothOLE DBandODBCproviders return incorrect/incomplete database schema, but those errors are specific only to one provider. When we merge schemas from both providers - we receive correct database schema for scaffolding. - support for generation of async stored procedure mappings
- more flexible identifier generation options
- extensibility hook to override type mapping of database type to .NET type
- added some more database types mappings to .net type in scaffolding (previously default type
objectused):- [Sybase]:
usmallint,uint,ubigint,bigdatetime,date,time,bigtime,unitext,unichar,univarchar - [Oracle]:
BINARY_INTEGER,INTERVAL DAY TO ...,INTERVAL YEAR TO MONTH - [PostgreSQL]:
regproc(as string), custom enum (as string, in future we can add C# enum generation), default multi-/range types (except custom range types) - scaffold tool will generate error message to console when unknown database type found. If this is standard type - it is recommended to report it as issue so we can add support for it. For custom types it is better to use extensibility hook to specify proper .net type for it.
- [Sybase]:
Thanks to Vyacheslav Avdeev for PR.
Remote data context allows Linq To DB to work with database indirectly by sending LINQ queries to server application over network. This feature were introduced long time ago mostly to facilitate database access for runtimes with limited functionality (e.g. currently dead Silverlight or mono-based mobile frameworks).
Initial implementation (pre-4 versions) supported only .NET Framework and two transports:
- WCF
- ASMX WebServices
With 4.0 release we refresh this feature to support modern frameworks and transports. List of changes:
- ASMX WebServices transport support removed (this is quite old technology nobody really should use for at least recent 10 years)
- GRPC transport added
- .NET (Core) support added (GRPC-only, WCF implementation currently limited to .NET Framework)
- WCF an GRPC transport implemntations support async transport APIs for async queries (previously all network requests used blocking API)
- Core functionality made public to allow new transport implementations by users
- Existing transports implementations moved to separate nugets: linq2db.Remote.Grpc and linq2db.Remote.Wcf
We can add more transports in future on request.
For use examples, check examples here (Remote folder).
You can also read about interceptors in Linq To DB here.
This release brings some changes to interceptors feature, introduced in earlier releases:
- added new
IUnwrapDataObjectInterceptorinterceptor to work with data connection wrappers, e.g. MiniProfiler - moved
EntityCreatedinterceptor event fromIDataContextInterceptorto separateIEntityServiceInterceptor - renamed
ConnectionOpenedEventDataandConnectionOpeningEventDatastructs toConnectionEventData - added
AfterExecuteReaderinterceptor toICommandInterceptorinterface
This interceptor is triggered after DbCommand.ExecuteReader(CommandBehavior) or DbCommand.ExecuteReaderAsync(CommandBehavior, CancellationToken) calls before reader enumeration. E.g. it could be used to modify reader options before data enumeration (Oracle provider could have such options).
void AfterExecuteReader(CommandEventData eventData, DbCommand command, CommandBehavior commandBehavior, DbDataReader dataReader);This interceptor replaces old approach, where you need to register unwrap expressions in MappingSchema.
Example of interceptor implementation for MiniProfiler:
public class UnwrapProfilerInterceptor : UnwrapDataObjectInterceptor
{
// as interceptor is thread-safe, we will create
// and use single instance of it
public static readonly IInterceptor Instance = new UnwrapProfilerInterceptor();
public override DbConnection UnwrapConnection(IDataContext dataContext, DbConnection connection)
{
return connection is ProfiledDbConnection c ? c.WrappedConnection : connection;
}
public override DbTransaction UnwrapTransaction(IDataContext dataContext, DbTransaction transaction)
{
return transaction is ProfiledDbTransaction t ? t.WrappedTransaction : transaction;
}
public override DbCommand UnwrapCommand(IDataContext dataContext, DbCommand command)
{
return command is ProfiledDbCommand c ? c.InternalCommand : command;
}
public override DbDataReader UnwrapDataReader(IDataContext dataContext, DbDataReader dataReader)
{
return dataReader is ProfiledDbDataReader dr ? dr.WrappedReader : dataReader;
}
}For additional examples and documentation check this article.
This new feature allows user to attach custom SQL to LINQ queries at several extension points. This allows user to use most of database-specific SQL statement extensions without downgrading to raw SQL queries. E.g.:
- specify database-specific query hints
- annotate queries or subqueries with custom comments
- other non-hint code
In previous versions of Linq To DB we had several API with for limited support for such extensions:
-
Withtable extension to add MSSQL-style table hintWITH(...) -
WithTableExpressiontable extension to add custom table hint -
DataConnection.QueryHintsandDataConnection.NextQueryHintsto add custom SQL as suffix or prefix to next query or queries. Those API are still available and supported. E.g.QueryHintsandNextQueryHintscould be useful with non-linq APIs, where new extensions API is not available.
For list of extension points check this table. More extension points could be added on user request in future.
Except extension API itself we added a lot of ready-to-use extensions (mostly hints) for supported databases. If you still cannot find some hint you need - create feature request. Available extensions:
-
LinqToDB.DataProvider.<DB_NAME>.<DB_NAME>Hintsextension classes with db-specific hints for tables, joins, (sub-)queries -
As<DB_NAME>()extension method inLinqToDB.DataProvider.<DB_NAME>namespace which could be used to specify extensions for use with specific database type. This is useful for applications that should work with multiple database types (e.g.OracleandPostgreSQL) and want to use same linq query code for them. -
QueryNameextension to set a name to (sub-)query which will be used as reference to query from query-specific hint (for databases with query naming support) -
TableId,Sql.TableName,Sql.TableSpec,Sql.TableAliasmethods to assign identifier to table for reference from hint. It is similar toQueryNamebut used for tables instead of (sub-)queries - hint methods
TableHint,TablesInScopeHint,IndexHint,JoinHint,SubQueryHintandQueryHint
To create your own extension you can use new Sql.QueryExtensionAttribute attribute. Check existing extensions for examples.
No new v4-specific features, only changes from underlying v3 releases:
- preview 10: updates from 3.6.0
- preview 9: updates from 3.5.2
- preview 8: updates from 3.5.1
- preview 7: updates from 3.5.0
- preview 6: updates from 3.4.5
- preview 5: updates from 3.4.4
- preview 4: updates from 3.4.3
- preview 3: updates from 3.4.2
- preview 2: updates from 3.4.1
With this release we start to publish previews of Linq To DB v4 (planned for release later this year). Previews will include all features and fixes from current v3 release and new features, fixes and refactorings for v4. This will allow users to use new features that require major version bump due to breaking changes without waiting for next major release.
Based on: v3.4.0. For migration notes check this document
-
#2728:
-
#2643: MARS-like queries support. This feature will unblock execution of queries inside of enumeration of another open query without force materialization (e.g. using
ToList()/ToAray()methods):- [SQL Server]:
MultipeActiveResutSets=trueconnection option required - [MySQL/MariaDB][PostgreSQL]: feature is not supported due to provider or database protocol limitation
- [SQL Server]:
- [BREAKING] Access to current command data for data connection changed to support multiple active commands:
-
DataConnection.LastParametersproperty removed -
DataConnection.Commandproperty removed - procedures, generated using T4 templates should be regenerated, as they were using removed properties
- to access
Command(on handle other events/extension points in future) we introduce interceptors support, similar to EF.Core interceptors with some distinctions (see below) - following
DataConnectionevents replaced with interceptors:OnBeforeConnectionOpen,OnBeforeConnectionOpenAsync,OnConnectionOpened,OnConnectionOpenedAsync
-
- [Sybase] Native bulk copy against temp table will automatically downgrade to SQL-based bulk copy implementation as native bulk copy doesn't support temp tables
-
#2643: MARS-like queries support. This feature will unblock execution of queries inside of enumeration of another open query without force materialization (e.g. using
- #2812: SQL Server 2000 support was removed (min. supported SQL Server version is 2005 from now). If you still need to support SQL Server 2000 you can use Linq To DB v3 or request support restore from us.
-
#2826: Adds
Guidtype support for Firebird provider. Thanks to Eugine Savin for contribution. By defaultGuidis mapped to FirebirdUUIDtype (CHAR(16) CHARACTER SET OCTETS). SpecifyingDataType = DataType.CharorDataType = DataType.NCharin mapping will map it toCHAR(38)-
#2823: properly generate type name for
Guid(e.g. forCreateTableAPI orCASTexpression) based usedDataType -
#2833: support literal generation for
Guidbased usedDataType - note that in previous versions of
Linq To DBGuidsupport was limited toCHAR(38)string literal generation for parameters and if you want to preserve mapping to string for your model, you should annotate it withDataType.Char
-
#2823: properly generate type name for
-
#2929: replace se of ADO.NET interfaces with corresponding base classes everywhere. Following changes done:
-
IDataRecord/IDataReader->DbDataReader -
IDbCommand->DbCommand -
IDbDataParameter->DbParameter -
IDbConnection->DbConnection -
IDbTransaction->IDbTransaction - [BREAKING]: if you had custom mappings that use those interfaces, they should be updated to use classes, e.g.:
-
MiniProfilerunwrap mappings - custom data reader expressions
-
-
-
#2930: remove functionality, marked in v3 with
[Obsolete]attribute - #2941:
With this release we are starting migration from events to interceptors and introduce first interceptor events. For initial release we concentrating on migration of already existed functionality (e.g. events) to interceptors. New events without prior implementation will be added later or on request.
To see which APIs were replaced with interceptors check migration notes
This interceptor provides access to events and operations associated with database command.
// triggered after command initialization but before execution
// it provides access to prepared SQL command and parameters
DbCommand CommandInitialized(CommandEventData eventData, DbCommand command);
// triggered before `ExecuteScalar/ExecuteScalarAsync` call on command
// and could replace actual call by returning results from interceptor
Option<object?> ExecuteScalar (
CommandEventData eventData,
DbCommand command,
Option<object?> result);
Task<Option<object?>> ExecuteScalarAsync(
CommandEventData eventData,
DbCommand command,
Option<object?> result,
CancellationToken cancellationToken);
// triggered before `ExecuteNonQuery/ExecuteNonQueryAsync` call on command
// and could replace actual call by returning results from interceptor
Option<int> ExecuteNonQuery (CommandEventData eventData, DbCommand command, Option<int> result);
Task<Option<int>> ExecuteNonQueryAsync(
CommandEventData eventData,
DbCommand command,
Option<int> result,
CancellationToken cancellationToken);
// triggered before `ExecuteReader/ExecuteReaderAsync` call on command
// and could replace actual call by returning results from interceptor
Option<DbDataReader> ExecuteReader (
CommandEventData eventData,
DbCommand command,
CommandBehavior commandBehavior,
Option<DbDataReader> result);
Task<Option<DbDataReader>> ExecuteReaderAsync(
CommandEventData eventData,
DbCommand command,
CommandBehavior commandBehavior,
Option<DbDataReader> result,
CancellationToken cancellationToken);
struct CommandEventData
{
public DataConnection DataConnection { get; }
}
// convinience base class for custom interceptor implementation
public abstract class CommandInterceptor : ICommandInterceptor
{
// interceptor implementation as no-op virtual methods
}This interceptor provides access to events and operations associated with database context (built-in class that implements IDataContext, e.g. DataConnection or DataContext).
// triggered when new entity created during query materialization
// (except queries with explicit constructor call)
object EntityCreated(DataContextEventData eventData, object entity);
// triggered before data context instance `Close/CloseAsync` method execution
void OnClosing(DataContextEventData eventData);
Task OnClosingAsync(DataContextEventData eventData);
// triggered after data context instance `Close/CloseAsync` method execution
void OnClosed(DataContextEventData eventData);
Task OnClosedAsync(DataContextEventData eventData);
struct DataContextEventData
{
public IDataContext Context { get; }
}
// convinience base class for custom interceptor implementation
public abstract class DataContextInterceptor : IDataContextInterceptor
{
// interceptor implementation as no-op virtual methods
}This interceptor provides access to events and operations associated with database connection.
// triggered before data connection `Open/OpenAsync` method execution
void ConnectionOpening(ConnectionOpeningEventData eventData, DbConnection connection);
Task ConnectionOpeningAsync(
ConnectionOpeningEventData eventData,
DbConnection connection,
CancellationToken cancellationToken);
// triggered after data connection `Open/OpenAsync` method execution
void ConnectionOpened(ConnectionOpenedEventData eventData, DbConnection connection);
Task ConnectionOpenedAsync(
ConnectionOpenedEventData eventData,
DbConnection connection,
CancellationToken cancellationToken);
struct ConnectionOpenedEventData
{
public DataConnection DataConnection { get; }
}
// convinience base class for custom interceptor implementation
public abstract class ConnectionInterceptor : IConnectionInterceptor
{
// interceptor implementation as no-op virtual methods
}To register interceptor you can use:
-
AddInterceptormethod on data context (e.g.DataConnectionorDataContext) - add interceptor to
LinqToDbConnectionOptionsusingLinqToDbConnectionOptionsBuilder.AddInterceptor(interceptor)API - for one-time execution of
ICommandInterceptor.CommandInitializedevent you can usedb.OnNextCommandInitialized(interceptor delegate)method onDataConnectionorDataContext
// registration in DataContext
using (var ctx = new DataContext(...))
{
ctx.AddInterceptor(interceptor);
// one-time command prepared interceptor
ctx.OnNextCommandInitialized((args, cmd) =>
{
// save next command parameters to external variable
parameters = cmd.Parameters.Cast<DbParameter>().ToArray();
return cmd;
});
}
// registration in DataConnection
using (var ctx = new DataConnection(...))
{
ctx.AddInterceptor(interceptor);
// one-time command prepared interceptor
ctx.OnNextCommandInitialized((args, cmd) =>
{
// set oracle-specific command option for next command
((OracleCommand)command).BindByName = false;
});
}
// registration in DataConnection using fluent configuration
var builder = new LinqToDbConnectionOptionsBuilder()
.UseSqlServer(connectionString)
.WithInterceptor(interceptor);
var dc = new DataConnection(builder.Build());