Skip to content

DynamicParameters.AddParameters(IDbCommand): identity-free self-apply - #2225

Merged
mgravell merged 2 commits into
mainfrom
dynamicparameters-apply
Aug 20, 2026
Merged

DynamicParameters.AddParameters(IDbCommand): identity-free self-apply#2225
mgravell merged 2 commits into
mainfrom
dynamicparameters-apply

Conversation

@mgravell

Copy link
Copy Markdown
Member

The full bag protocol — per-parameter DbType/direction/size/precision/scale, 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 apply a parameter bag without reimplementing the protocol.

The immediate consumer is Dapper.AOT: its generated command factories can now support DynamicParameters arguments by delegating to the bag itself — which gives exact vanilla behavior for the whole surface (including Get<T> output reads and IParameterCallbacks) because it is the vanilla implementation. The generator probes for this symbol, so it activates only when the referenced Dapper has it; no coordination needed on release timing.

Test covers the bag + literal-replacement composition against a closed connection (no database needed). API registered in PublicAPI.Unshipped.txt.

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).
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.
@mgravell

Copy link
Copy Markdown
Member Author

Pushed a follow-up: the overload now dispatches via (SqlMapper.IDynamicParameters)this rather than calling the protected method directly. A subclass that hides AddParameters and re-implements the interface — the DynamicParameterWithIntTVP pattern from this repo's own test suite — was otherwise skipped, because the direct call binds statically to the base method. Test added for the hiding-subclass shape.

@mgravell
mgravell merged commit 41d76c7 into main Aug 20, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant