Allow to configure properties on non-collection complex types by using chaining in the lambda expression#38154
Allow to configure properties on non-collection complex types by using chaining in the lambda expression#38154AndriySvyryd wants to merge 1 commit intomainfrom
Conversation
There was a problem hiding this comment.
Pull request overview
Note
Copilot was unable to run its full agentic suite in this review.
This PR enables configuring nested (non-collection) complex type properties via chained member-access lambdas and dotted-string property paths, adding supporting builder plumbing, error messages, and specification tests (Fixes #31236).
Changes:
- Added complex-property chain resolution for lambda-based configuration and dotted string names (including auto-creation for lambda intermediates).
- Introduced new CoreStrings messages for invalid chained/dotted cases (invalid segment, invalid intermediate, collection intermediate, missing intermediate).
- Expanded model-building tests to validate chained/dotted configuration scenarios and failure modes.
Reviewed changes
Copilot reviewed 16 out of 17 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| test/EFCore.Specification.Tests/ModelBuilding/ModelBuilderTest.TestModel.cs | Adds new nested complex CLR types used by the new chaining tests. |
| test/EFCore.Specification.Tests/ModelBuilding/ModelBuilderTest.OwnedTypes.cs | Adds tests ensuring owned navigations are rejected as chain intermediates. |
| test/EFCore.Specification.Tests/ModelBuilding/ModelBuilderTest.NonGeneric.cs | Updates non-generic test wrappers to pass dotted names derived from member chains. |
| test/EFCore.Specification.Tests/ModelBuilding/ModelBuilderTest.ComplexType.cs | Adds extensive tests for chained lambda and dotted-name configuration of nested complex members. |
| test/EFCore.Specification.Tests/ModelBuilding/ModelBuilderTest.ComplexCollections.cs | Adds a dotted-name test for configuring a nested complex collection. |
| src/EFCore/Properties/CoreStrings.resx | Adds new error message resources for complex-property chain resolution failures. |
| src/EFCore/Metadata/Internal/InternalTypeBaseBuilder.cs | Adds member-chain overloads for Property/PrimitiveCollection/ComplexProperty/Ignore. |
| src/EFCore/Metadata/Builders/EntityTypeBuilder`.cs | Enables chained lambda member access for generic entity type builder APIs. |
| src/EFCore/Metadata/Builders/EntityTypeBuilder.cs | Adds dotted-name support to non-generic builder overloads. |
| src/EFCore/Metadata/Builders/ComplexPropertyChainHelper.cs | New helper to parse/resolve member chains and dotted paths through complex types. |
| src/EFCore/Metadata/Builders/ComplexPropertyBuilder`.cs | Enables chained lambda member access for complex property builder APIs. |
| src/EFCore/Metadata/Builders/ComplexPropertyBuilder.cs | Adds dotted-name support to non-generic complex property builder overloads. |
| src/EFCore/Metadata/Builders/ComplexCollectionBuilder`.cs | Enables chained lambda member access for complex collection builder APIs. |
| src/EFCore/Metadata/Builders/ComplexCollectionBuilder.cs | Adds dotted-name support to non-generic complex collection builder overloads. |
| src/EFCore/Extensions/Internal/ExpressionExtensions.cs | Adds MatchMemberAccessChain() to extract chained member accesses from lambdas. |
| src/EFCore/EFCore.baseline.json | Updates API baseline for newly-added CoreStrings members. |
Files not reviewed (1)
- src/EFCore/Properties/CoreStrings.Designer.cs: Language not supported
19aabc9 to
f590cd9
Compare
1c9a825 to
d94e0d4
Compare
…g chaining in the lambda expression Fixes #31236
d94e0d4 to
3fb9956
Compare
| var (innerBuilder, leafName) = Builder.ResolveComplexChainByName(propertyName); | ||
| return new PropertyBuilder(innerBuilder.Property(leafName, ConfigurationSource.Explicit)!.Metadata); |
There was a problem hiding this comment.
nit: if we want to keep nicer/shorter expression-based code, we can have a method on Builder which accepts the name and a lambda, and internally resolved the inner builder and invokes the lambda on it. Callers would then pass (static) lambdas doing the actual call (Property, PrimitiveCollection).
| var metadata = builder.Metadata; | ||
|
|
||
| var conflictingMember = metadata.FindMembersInHierarchy(memberName).FirstOrDefault(); | ||
| if (conflictingMember is ComplexProperty { IsCollection: true }) |
There was a problem hiding this comment.
nit: can be a 3-legged switch statement (also below).
Fixes #31236