Fix NRE in FindJsonPartialUpdateInfo when replacing TPH derived entity with owned JSON#37823
Conversation
…placing derived entity (#36019) Add test `Replace_derived_entity_with_json_to_different_derived_type_with_same_key` that reproduces NullReferenceException when removing a derived TPH entity with an owned JSON type and adding a different derived entity without JSON but with the same composite key. Fix: In `FindJsonPartialUpdateInfo`, check if `FindPrincipal` returns null (which happens when the principal entity was replaced with a different derived type in TPH) and return null to skip JSON-specific processing, consistent with the existing pattern for deleted parent entities. Co-authored-by: AndriySvyryd <[email protected]>
… test model conventions Co-authored-by: AndriySvyryd <[email protected]>
…back Co-authored-by: AndriySvyryd <[email protected]>
…tionalFixture Co-authored-by: AndriySvyryd <[email protected]>
…of new Tph classes Co-authored-by: AndriySvyryd <[email protected]>
test/EFCore.SqlServer.FunctionalTests/Update/JsonUpdateJsonTypeSqlServerTest.cs
Show resolved
Hide resolved
There was a problem hiding this comment.
Pull request overview
Fixes a NullReferenceException in EF Core’s relational update pipeline when a TPH derived entity with owned JSON dependents is deleted and replaced by a base (or different derived) entity using the same key, causing JSON-owned dependents to lose their principal during partial-update path discovery.
Changes:
- Added a null guard in
ModificationCommand.FindJsonPartialUpdateInfoto handleFindPrincipal(...)returningnull. - Added a relational specification test covering “replace derived-with-JSON → base with same key”.
- Hooked the new test into the SQL Server JSON type functional test suite (override to satisfy the “all tests overridden” check).
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| src/EFCore.Relational/Update/ModificationCommand.cs | Prevents NRE by handling null principals when walking up JSON-owned entry ownership chain. |
| test/EFCore.Relational.Specification.Tests/Update/JsonUpdateTestBase.cs | Adds regression test reproducing the TPH replacement scenario with derived-only JSON navigations. |
| test/EFCore.SqlServer.FunctionalTests/Update/JsonUpdateJsonTypeSqlServerTest.cs | Overrides the new base test for the SQL Server JSON type suite (consistent with existing override coverage checks). |
…tity_with_same_key in JsonUpdateJsonTypeSqlServerTest Co-authored-by: AndriySvyryd <[email protected]>
…Principal call Co-authored-by: AndriySvyryd <[email protected]>
|
@copilot Update description with a nice summary of the changes |
Updated the PR description with a summary covering the root cause (orphaned JSON entries from derived-only navigations after TPH entity replacement), the fix (nullable |
Fixes #36019
Fixes a
NullReferenceExceptioninModificationCommand.FindJsonPartialUpdateInfowhen a TPH derived entity with owned JSON columns is removed and replaced by a base entity using the same primary key.When replacing a
JsonEntityInheritanceDerivedwith aJsonEntityInheritanceBasesharing the same key, the deleted derived entity's JSON-owned dependents (e.g.ReferenceOnDerived,CollectionOnDerived) still appear as modified entries. During partial-update path discovery,FindPrincipalreturnsnullfor these orphaned JSON entries because their principal no longer exists in the change tracker—the new base entity doesn't have those derived-only navigations. The code previously assumedFindPrincipalwould always return non-null, causing the NRE.Fix: Made
currentEntrynullable insideFindJsonPartialUpdateInfo, removed the null-forgiving operator from theFindPrincipalcall, and added explicit null handling in the loop condition and null-coalescing downstream. WhenFindPrincipalreturnsnull, the method now returnsnull(skipping JSON partial update for that entry), which allows the update pipeline to proceed correctly.Test: Added
Replace_derived_entity_with_json_to_base_entity_with_same_keyregression test using the existingJsonEntityInheritanceBase/JsonEntityInheritanceDerivedhierarchy, with SQL baseline assertion for SQL Server.💡 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.