Skip to content

feat(mapping): collection-mapped properties with multi-result-set read handler - #4

Open
dtraft wants to merge 1 commit into
masterfrom
collection-mapping
Open

feat(mapping): collection-mapped properties with multi-result-set read handler#4
dtraft wants to merge 1 commit into
masterfrom
collection-mapping

Conversation

@dtraft

@dtraft dtraft commented Sep 8, 2026

Copy link
Copy Markdown

Posted by: Claude Code (Claude Fable 5.1) | 2026-09-08

TL;DR

Adds collection-mapped model properties to the core mapper: a provider-agnostic CollectionMapAttributeBase, the write-side hook in Mapper.IterateInMapProperties, and a new read-side handler that hydrates each collection property from its own result set. Enables a single model (for example Orleans grain state) to round-trip a parent row plus owned child rows in one query.

Changes

  • Mapping/CollectionMapAttributeBase.cs (new): abstract attribute for collection properties; providers supply the structured-parameter expression (ArgentSea.Sql implements it as a table-valued parameter).
  • Mapping/Mapper.cs: IterateInMapProperties detects the attribute and emits the provider's collection-parameter expression (element type resolved for ImmutableArray<T> and any IEnumerable<T>). New ModelFromReaderWithCollectionsHandler<TModel> (a QueryResultModelHandler-compatible method): maps the first result set into the model via the existing single-row path, then for each collection property in declaration order (sorted by MetadataToken) reads the NEXT result set with the existing ToList<TElement> row lambdas. A missing result set throws UnexpectedSqlResultException naming the model, property and expected position -- a present-but-empty result set yields an empty collection. Hydration delegates are compiled once per model type and cached.
  • Databases.cs and ShardDataConnection.cs: MapReaderWithCollectionsAsync<TModel> overloads mirroring the existing MapReaderAsync shapes.

Models without the attribute take exactly the existing code paths.

Testing

  • Existing ArgentSea.Test suite: 45 passed, 0 failed.
  • Behavior is exercised end to end by the ArgentSea.Sql PR's new CollectionMapReadTests / CollectionMapWriteTests (11 tests: one and two collections, declaration order, empty child result set, missing child result set throws, missing record returns null without touching NextResult, attribute-less model unchanged).
  • Consumed live by a downstream application: an Orleans grain whose state carries two ImmutableArray<T> collections, written as TVPs and read back as three result sets against SQL Server.

Dependencies

First of a four-PR set: argentsea/shared -> argentsea/sql -> argentsea/Orleans -> argentsea/Orleans.Sql. The other three reference this project and build against these changes.

Related PRs (merge in this order)

  1. feat(mapping): collection-mapped properties with multi-result-set read handler #4
  2. feat(mapping): MapToSqlTableValuedParameter attribute and empty/struct TVP fixes sql#2
  3. feat(persistence): hydrate CollectionMap grain-state properties from extra result sets Orleans#5
  4. fix(persistence): resolve named OrleansDbPersistenceOptions in the Db storage factory Orleans.Sql#3

…d handler

> Claude Code (Claude Fable 5.1)

Adds CollectionMapAttributeBase, the write-side hook in Mapper.IterateInMapProperties, and ModelFromReaderWithCollectionsHandler plus MapReaderWithCollectionsAsync overloads, so a model can round-trip a parent row and owned child collections in one query. Collection properties hydrate from subsequent result sets in declaration order; a missing result set throws rather than yielding an empty collection. Models without the attribute keep their existing code paths.
@dtraft
dtraft force-pushed the collection-mapping branch from 21f1531 to a3b3d0a Compare September 8, 2026 19:04
@dtraft
dtraft marked this pull request as ready for review September 9, 2026 12:50
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