A subclass that hides AddParameters and re-implements the interface - the
DynamicParameterWithIntTVP pattern from this very test suite - was skipped
by the direct call, which binds statically to the protected base method.
Routing through the interface uses the runtime type's interface map, so
the subclass version runs, matching what vanilla execution does.
The full bag protocol (per-parameter DbType/direction/size, templates,
literal replacement, RemoveUnused) already lives in AddParameters(command,
identity), but the identity requirement makes it uncallable from outside:
Identity's constructor is internal, and identity.Sql is consumed on the
first line. This overload builds the identity from the command's own text
and type, which is what identity.Sql is in practice - letting external
tooling (for example build-time code generators, aka Dapper.AOT) apply a
bag without reimplementing the protocol.
Test covers the bag+literal composition against a closed connection (no
database needed).
The site was running on GitHub's defaults, which take the title and description
from the repo's name and description fields - so an edit in the repo settings UI
quietly changed the site's metadata. Those are pinned now, along with the URL,
which is what jekyll-seo-tag uses to build canonical and og:url.
Also: strip_title, so the page title stops being printed twice (once in the
theme's header banner, once as the heading it was derived from); jekyll-sitemap,
which is not in the always-on GitHub Pages plugin set, for the sitemap.xml and
robots.txt the site did not have; and a favicon built from the project logo,
hooked up via the head-custom.html include the theme provides for exactly this.
Claude-Session: https://claude.ai/code/session_01NxkjXSR7CSGzyw89tJJVtw
Release note tracking moved to GitHub Releases some time ago; docs/index.md says so and keeps only an archive below that point. PackageReleaseNotes was still pointing at the docs root, so anyone following it from NuGet landed on the archive and had to make one more hop.
The docs site now has its own domain. The old dapperlib.github.io URLs still work via a redirect, but there's no reason to keep going the long way round, and PackageReleaseNotes in particular is baked into every package we publish.
Also switches PackageProjectUrl to the docs site, matching DapperAOT; RepositoryUrl still points at the source.
* Add Settings.PreferTypeHandlersForEnums opt-in flag
When enabled, Dapper checks for a registered TypeHandler for enum types
before falling back to the default integer boxing behavior. This allows
custom enum serialization (e.g. storing enums as strings via TypeHandlers)
to work on both reads and writes.
Patched locations:
- LookupDbType: return DbType.Object with handler when flag is on
- CreateParamInfoGenerator: skip integer boxing when handler exists
- GetSimpleValueDeserializer: route to TypeHandler before Enum.ToObject
- Parse<T>: route to TypeHandler before Enum.ToObject
Default is false — zero behavior change for existing users.
* Patch IL-emitted type deserializer and add tests
- Fix 6th enum-before-handler location in GetTypeDeserializer IL emit,
preserving Nullable<T> wrapping for nullable enum properties
- Fix em-dash in comment (non-ASCII)
- Add two tests: round-trip write+read via StringEnumHandler, and
nullable enum with null value
* Update SDK version from 10.0.102 to 8.0.100
* Update global.json
we have fixed the CI glitch separately
---------
Co-authored-by: Marc Gravell <marc.gravell@gmail.com>
The IL emitted by CreateParamInfoGenerator used Callvirt to invoke
AddParameter on an unboxed struct sitting on the evaluation stack.
Callvirt expects a reference, so the CLR misinterpreted the raw struct
bytes as an object pointer, causing a fatal CLR error (0x80131506).
* - mark AddTypeHandlerImpl as obsolete
- syncronize type-handler mutates, to prevent lost writes
* CI: revert pgsql uddate
* suppress Impl's use of clone: false
* avoid additional local snapshot, now that we're synchronized
* explicitly request postgresql96
* more pgsql poking
* pg path fix
* see #2115
- correctness: do no use SingleRow by default; affects trailing errors
- performance: QueryUnbufferedAsync can mirror cmd?.Cancel() in finally (this is consistent with all other scenarios)
* remove settings tweak
When disposing wrapped readers, only call Dispose() on the inner reader and let it catch exceptions if appropriate.
Note: this actually happened with `Microsoft.Data.SqlClient`.
```
Microsoft.Data.SqlClient.SqlException (0x80131904): Execution Timeout Expired. The timeout period elapsed prior to completion of the operation or the server is not responding.
---> System.ComponentModel.Win32Exception (258): The wait operation timed out.
at void Microsoft.Data.SqlClient.SqlConnection.OnError(SqlException exception, bool breakConnection, Action<Action> wrapCloseInAction)
at void Microsoft.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, bool callerHasConnectionLock, bool asyncClose)
at bool Microsoft.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, out bool dataReady)
at bool Microsoft.Data.SqlClient.SqlDataReader.TryCloseInternal(bool closeReader)
at void Microsoft.Data.SqlClient.SqlDataReader.Close()
at void Dapper.DbWrappedReader.Dispose(bool disposing) in /_/Dapper/WrappedReader.cs:line 149
at ValueTask System.Data.Common.DbDataReader.DisposeAsync()
```