Fix NullReferenceException when accessing null complex properties in TPH with shared columns#37695
Conversation
…es in TPH Co-authored-by: AndriySvyryd <6539701+AndriySvyryd@users.noreply.github.com>
test/EFCore.SqlServer.FunctionalTests/ComplexTypesTrackingSqlServerTest.cs
Show resolved
Hide resolved
…tself is complex The NRE was occurring during SaveChanges when setting properties inside a null complex type. The original fix incorrectly checked if the property itself was a complex property, but it should check if the property is declared in a complex type. When accessing Amount inside SharedPrice, Amount is a scalar property but its declaring type (SharedPrice) is a complex type. Co-authored-by: AndriySvyryd <6539701+AndriySvyryd@users.noreply.github.com>
The NRE was occurring in AcceptChanges when trying to set store-generated values on properties inside null complex types. Added check to skip properties declared in complex types when the complex type instance is null, following the same pattern used elsewhere in the codebase (lines 1612-1613, 1627-1628). Co-authored-by: AndriySvyryd <6539701+AndriySvyryd@users.noreply.github.com>
test/EFCore.SqlServer.FunctionalTests/ComplexTypesTrackingSqlServerTest.cs
Outdated
Show resolved
Hide resolved
…rning Added .Where(i => i.Name == "Item1") filter before FirstAsync() calls to avoid the warning about using First without OrderBy and filter operators. This makes the tests more deterministic and follows EF Core testing best practices. Co-authored-by: AndriySvyryd <6539701+AndriySvyryd@users.noreply.github.com>
test/EFCore.SqlServer.FunctionalTests/ComplexTypesTrackingSqlServerTest.cs
Show resolved
Hide resolved
Modified PropertyAccessorsFactory to only add null checks when the complex property is actually nullable (IsNullable=true). This prevents adding unnecessary null checks in compiled models for required complex properties while still protecting against NRE for nullable complex properties in TPH scenarios with shared columns. Co-authored-by: AndriySvyryd <6539701+AndriySvyryd@users.noreply.github.com>
Instead of modifying PropertyAccessorsFactory and AcceptChanges, fix the issue at its source in TryPropagate. When a property belongs to a complex type whose containing complex property is currently null, TryPropagate now returns early without attempting to propagate the value, preventing the NRE. Fixes #37335 Co-authored-by: AndriySvyryd <6539701+AndriySvyryd@users.noreply.github.com>
Done in 22c592e. Reverted changes to |
There was a problem hiding this comment.
Pull request overview
This PR fixes a NullReferenceException that occurs when saving entities in a Table-Per-Hierarchy (TPH) inheritance scenario where two derived types share a nullable complex property mapped to the same database column. The exception was thrown during value propagation when the complex property was null.
Changes:
- Added an early return in
ColumnValuePropagator.TryPropagateto skip value propagation when a property belongs to a null complex type instance - Added comprehensive test coverage for both null and non-null complex property scenarios in TPH
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
| src/EFCore.Relational/Update/ModificationCommand.cs | Added null check for complex property instances before attempting to access their child properties during value propagation |
| test/EFCore.SqlServer.FunctionalTests/ComplexTypesTrackingSqlServerTest.cs | Added test methods, model classes, and fixture configuration to verify the fix handles TPH with shared complex property columns |
When two derived types in TPH share a nullable complex property mapped to the same column, saving an entity with a null complex property throws a
NullReferenceExceptionduring value propagation.Changes
The fix adds an early return in
ColumnValuePropagator.TryPropagate(ModificationCommand.cs) to skip propagation when the property belongs to a complex type whose containing complex property is currently null. This prevents the NRE at its source — the value propagation layer.Test coverage
Added tests in
ComplexTypesTrackingSqlServerTestfor TPH scenarios with shared complex property columns:Can_read_original_values_with_TPH_shared_complex_property_column_null— validates save and original values access when complex property is nullCan_read_original_values_with_TPH_shared_complex_property_column_with_value— validates save and original values access when complex property has a value💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.