Repository navigation
Commands take the type in their async terminals (ToArrayAsync<int>(ct)), and Map<int>() reads the first column - #111
Merged
Conversation
…async terminals that take the type Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
…s of a command and their binding Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
…g one column Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
…ne, => on its own line, doc comments wrapped at natural breaks Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
…d (IDE0011) Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
electricessence
marked this pull request as ready for review
November 10, 2026 16:26
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
electricessence
added a commit
that referenced
this pull request
Nov 11, 2026
Co-Authored-By: Claude Opus 5.5 <[email protected]>
This was referenced Nov 11, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What changes
await db.Command(sql).ToArrayAsync<int>(ct)now works, with no.Map(static r => r.GetInt32(0)). Two things make that so:Map<T>()of a single value reads the first column. A primitive, an enum,string,decimal,DateTime,DateTimeOffset,TimeSpan,DateOnly,TimeOnly,Guid,byte[]or aNullable<>of one is read from column 0 of each row, whatever it is named; other columns are ignored. The column is read as the mapper reads a property of that type: the typed getter when the column type matches (no boxing), range-checked integer narrowing, elseConvert. A NULL into a non-nullableTisdefault(T);int?,stringandbyte[]getnull. This reverses the rc.3 behaviour whereMap<int>()threw (whats-new-11 item 9 is rewritten). It is built insideRowMap<T>from the helpers the property mapper already uses (a small internalFirstColumn<T>row source);RowMap<int>.Default,Results<int>(),ToChannel<int>()and the other entry points still throw, with a message that now namesMap<T>()andToListAsync<T>().DateOnlyandTimeOnlywere misjudged as row models before (a misleading "N public constructors" message); they are single values now.IExecuteReader, each one expression,Map<T>()then the terminal, token last:ToListAsync<T>,ToArrayAsync<T>,ToImmutableArrayAsync<T>,FirstOrDefaultAsync<T>,SingleOrDefaultAsync<T>,ToHashSetAsync<T>(comparer = null, cancellationToken = default). For a row model they equalMap<T>().ToXAsync(). An unmappableTthrows at the call, before anything runs.Owner decision: only the async shortcuts are on the command; the synchronous versions stay at the reader level. There are no sync forwarders, so a sync caller writes
command.Map<int>().ToList()(which works because of the first bullet). Nothing that exists changed.Binding notes (pinned by a compile-only test file): no call that compiled before changes binding.
cmd.ToListAsync<int>(default)or(null)on an expressive command still binds to the obsolete instanceToListAsync(transform, behavior); pass the token or nothing.ToHashSetAsync<int>(ct)does not compile (the comparer comes first, as onMappedQuery<T>): writecancellationToken: ct.One deviation from the plan, which said a reader that reports no columns would give a ValueMappingException: a reader that reports no columns but has a row throws the provider's IndexOutOfRangeException unwrapped. The code is left as it is and SingleValueTerminalTests pins it.
Docs
mapping.md: new section "One value per row" (which types, first column, conversion, NULL, read through, how it differs fromFirstOrdinalResults<T>()andExecuteScalar<T>()); the errors table row and theSingleResultexample useMap<int>().whats-new-11.md: highlights, NULL rules, a bullet "Commands take the type, asynchronously", and upgrading item 9 rewritten (Map<int>()reads the first column; 10.x returneddefault(T)).expressive-commands.md(terminals table, which scalar form, a sample),foundation.md,coming-from-dapper.md(Query<int>row,QueryAsync<T>).ToListAsync<T>, inherited by the others) and onMap<T>()andRowMap<T>.Mapping.cs,ExpressiveCommands.cs) with checks inProgram.cs.Tests
SingleValueTerminalTests: every single-value type from a column of its own type; NULL in first and later rows; conversions (long to int, overflow asValueMappingException, decimal, text, enum, Guid); extra columns and column order; empty results; async parity withMap<T>()forint,int?,stringand a row model; an unmappableTthrows at the call with nothing executed; read through later result sets and.SingleResult(); token combining; aDbDataReaderand a plainIDataReader; the per-result-set cache keyed by column type; a column that changes type mid-set.SingleValueBindingTests: a compile-only table of every call form, plus the(default)trap.SingleValueAllocationTests:Map<int>()andToListAsync<int>()allocate no more than the hand-written selector (no per-row boxing).UnmappableTypeTests: single values now passMap<T>(); the six async terminals join the "every entry point" theories.Checks
Master, with #110 and #112, is merged in. The only conflicts were in
PublicAPI.Unshipped.txt, where both sides' lines are kept, and in onewhats-new-11.mdbullet, where master's token wording is kept. From the gate (verify-gate.ps1) on the merged head: the Release and Debug builds have 0 warnings and 0 errors; Core tests: 9508 passed, 0 failed, in Release and in Debug; the samples build with 0 warnings and "All 98 sample checks passed."; style and analyzers on every project, all target frameworks, info level: 0 findings; DocFX: 0 warnings, 0 errors.The last three commits only reformat the lines this PR adds: one parameter per line,
=>on its own line, doc comments wrapped at natural breaks. The style analyzer (IDE0011) then asked for braces on two multi-lineif/elsebodies, inRowMap.csandUnmappableTypeTests.cs. Every changed file was compared with its previous version: the code, with whitespace removed, and the comment text are unchanged apart from those braces.Not in this change
Synchronous command shortcuts (owner decision).
ToDictionary,Read,Skip/Takeon the command. RawIDbCommand/DbCommand/IDataReaderreceivers.Half,Int128,BigIntegerandobjectas single values. The benchmark pair (Map(selector)vsMap<int>()vs Dapper) is not run here.🤖 Generated with Claude Code