Skip to content

command.SingleResult().Map<T>(): the opt-out reads as behavior, then shape - #127

Merged
electricessence merged 5 commits into
masterfrom
feat/single-result-before-map
Nov 12, 2026
Merged

electricessence merged 5 commits into
masterfrom
feat/single-result-before-map

Conversation

@electricessence

Copy link
Copy Markdown
Collaborator

command.SingleResult().Map<T>(): the opt-out reads as behavior, then shape.

// Before: only after Map
var rows = await command.Map<Post>().SingleResult().ToListAsync(ct);

// Now, also before Map (identical meaning)
var rows = await command.SingleResult().Map<Post>().ToListAsync(ct);

What

  • SingleResult() is now an extension on IExecuteReader (expressive commands) and on IDbCommand (raw commands), usable before Map. x.SingleResult().Map<T>() is exactly x.Map<T>().SingleResult(), for every terminal, sync and async. The after-Map form still works.
  • SingleResult() is the one explicit opt-out of the library's read-through: the query reads the first result set and stops, so a failure in a later statement is not seen. That behavior and every default are unchanged. It is not on IDataReader or DataTable, which are single-result already.
  • New public surface: the two extension methods, SingleResult(this IExecuteReader) and SingleResult(this IDbCommand). No new public type: they return an internal wrapper that carries the flag. Map unwraps it and runs against the ORIGINAL command with the query's existing single-result flag, so nothing on the Map path executes through the wrapper, and the caller's command is never changed.
  • A caller who uses the returned view directly as a command gets one that forwards every member and adds CommandBehavior.SingleResult to each reader it opens. Disposing that view disposes the command (documented).

Notes for review

  • The before-Map form allocates one small wrapper object per query; the after-Map form allocates nothing.
  • A type of your own that implements both IExecuteReader and IDbCommand gets CS0121 on SingleResult(), as it already does on Map.

Docs

  • The SingleResult remarks and the multiple-result-sets text in mapping.md now show the before-Map form first and mention that the after-Map form works; whats-new-11.md has an entry.

Tests

  • 154 cases: both forms compared on every terminal (ToList, ToArray, ToImmutableArray, FirstOrDefault, SingleOrDefault, ToDictionary, ToHashSet, Read, Skip, Take, Skip+Take, Take+FirstOrDefault), sync and async, for an expressive command, a DbCommand and a plain IDbCommand; a later-set failure is thrown without the opt-out and not with it (text and stored-procedure commands); the five Map overloads bind and Skip/Take keep the flag; the after-Map form alone and combined; the command is not mutated; null throws; both tokens cancel; compile-only binding for ExpressiveSqlCommand from both SQL Server packages, ExpressiveCommand, ExpressiveDbCommand, SqlCommand, DbCommand and IDbCommand.

Checks

  • Release and Debug builds: 0 warnings, 0 errors. Tests: 9831 of 9831 pass in both. Samples: 103 of 103 checks pass. Style and analyzers: 0 findings. DocFX: 0 warnings.

🤖 Generated with Claude Code

electricessence and others added 5 commits November 12, 2026 04:19
…shape

SingleResult() on an IExecuteReader or an IDbCommand returns a view whose Map overloads set the single-result
flag, so it is exactly command.Map<T>().SingleResult(). The after-Map form still works.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…d; restore the lambda's return

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@electricessence
electricessence merged commit a75d0dd into master Nov 12, 2026
2 checks passed
@electricessence
electricessence deleted the feat/single-result-before-map branch November 12, 2026 14:54
electricessence added a commit that referenced this pull request Nov 12, 2026
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
electricessence added a commit that referenced this pull request Nov 12, 2026
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
electricessence added a commit that referenced this pull request Nov 12, 2026
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
electricessence added a commit that referenced this pull request Nov 12, 2026
Conflicts: the SingleResult wording in mapping.md and the MappedQuery remarks keep master's text with this branch's
First and Single additions; whats-new keeps both sets of bullets.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
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