Skip to content

FIX Insert order bug when using TPC - Issue #35978 #38070

Merged
AndriySvyryd merged 2 commits intodotnet:mainfrom
andrewraper-Sage:tpc-insert-fix
Apr 17, 2026
Merged

FIX Insert order bug when using TPC - Issue #35978 #38070
AndriySvyryd merged 2 commits intodotnet:mainfrom
andrewraper-Sage:tpc-insert-fix

Conversation

@andrewraper-Sage
Copy link
Copy Markdown
Contributor

When using TPC inheritance with abstract base types, SaveChanges produces an incorrect INSERT order - child entities are inserted before their parents, causing FK constraint violations.

This happens because CommandBatchPreparer.AddForeignKeyEdges() fails to create dependency edges for FKs whose principal is an abstract TPC type mapped to no table. Since no IForeignKeyConstraint is created for such FKs, the table-level constraint path finds nothing.

The model-level FK fallback path should handle this, but for INSERT ordering it was skipped by a guard that assumed table-level constraints would cover it, and for DELETE ordering it was gated behind command.Table == null (unreachable for concrete TPC entities which always have a table).

The fix ensures the model-level FK path participates in dependency edge creation when no mapped table-level constraint exists: an additional foreignKey.GetMappedConstraints().Any() check on the INSERT principal registration guard, and removing the else gates on both DELETE paths so they always run alongside the table-level path (CanCreateDependency already prevents double-counting for FKs that do have mapped constraints).

Fixes #35978

@andrewraper-Sage
Copy link
Copy Markdown
Contributor Author

@andrewraper-Sage please read the following Contributor License Agreement(CLA). If you agree with the CLA, please reply with the following information.

@dotnet-policy-service agree [company="{your company}"]

Options:

  • (default - no company specified) I have sole ownership of intellectual property rights to my Submissions and I am not making Submissions in the course of work for my employer.
@dotnet-policy-service agree
  • (when company given) I am making Submissions in the course of work for my employer (or my employer has intellectual property rights in my Submissions by contract or applicable law). I have permission from my employer to make Submissions and enter into this Agreement on behalf of my employer. By signing below, the defined term “You” includes me and my employer.
@dotnet-policy-service agree company="Microsoft"

Contributor License Agreement

@dotnet-policy-service agree company="Sage"

@andrewraper-Sage andrewraper-Sage marked this pull request as ready for review April 9, 2026 12:25
@andrewraper-Sage andrewraper-Sage requested a review from a team as a code owner April 9, 2026 12:25
Copilot AI review requested due to automatic review settings April 9, 2026 12:25
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes incorrect SaveChanges command ordering for TPC inheritance when a foreign key’s principal is an abstract TPC type mapped to no table (preventing FK constraint violations by ensuring principals are ordered before dependents on INSERT, and dependents before principals on DELETE).

Changes:

  • Update CommandBatchPreparer.AddForeignKeyEdges() to include the model-level FK dependency path when no mapped table-level FK constraints exist.
  • Remove else gating so model-level FK dependency detection runs alongside the table-level constraint path (with CanCreateDependency preventing duplicates).
  • Add regression tests covering INSERT and DELETE ordering for the abstract-TPC-principal scenario.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

File Description
src/EFCore.Relational/Update/Internal/CommandBatchPreparer.cs Ensures dependency edges are created via model-level FK logic when table-level constraints are missing, fixing ordering for abstract TPC principals.
test/EFCore.Relational.Tests/Update/CommandBatchPreparerTest.cs Adds regression tests validating correct batching/sort order for Added and Deleted entities under abstract-principal TPC FKs.

Copilot AI review requested due to automatic review settings April 13, 2026 08:52
@andrewraper-Sage andrewraper-Sage marked this pull request as draft April 13, 2026 08:55
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

Comment thread src/EFCore.Relational/Update/Internal/CommandBatchPreparer.cs
Comment thread test/EFCore.Relational.Tests/Update/CommandBatchPreparerTest.cs
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 4 comments.

Comment thread src/EFCore.Relational/Update/Internal/CommandBatchPreparer.cs Outdated
Comment thread src/EFCore.Relational/Update/Internal/CommandBatchPreparer.cs Outdated
Comment thread test/EFCore.Relational.Tests/Update/CommandBatchPreparerTest.cs
Comment thread src/EFCore.Relational/Update/Internal/CommandBatchPreparer.cs Outdated
@andrewraper-Sage andrewraper-Sage marked this pull request as ready for review April 13, 2026 11:12
Copilot AI review requested due to automatic review settings April 13, 2026 11:12
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

Comment thread src/EFCore.Relational/Update/Internal/CommandBatchPreparer.cs Outdated
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

Comment thread src/EFCore.Relational/Update/Internal/CommandBatchPreparer.cs Outdated
Copilot AI review requested due to automatic review settings April 15, 2026 12:54
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

Comment thread src/EFCore.Relational/Update/Internal/CommandBatchPreparer.cs Outdated
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

Comment thread src/EFCore.Relational/Update/Internal/CommandBatchPreparer.cs Outdated
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated no new comments.

@andrewraper-Sage andrewraper-Sage marked this pull request as draft April 15, 2026 14:33
When using TPC with an abstract principal type mapped to no table, FK
dependency edges were not created because the code relied on mapped FK
constraints, which don't exist for abstract TPC types.

Fix:
- In the ADD predecessor registration loop, add a guard so that FKs with
  no mapped constraints (TPC abstract principal) are not skipped by the
  IsStoreGenerated check.
- In the DELETE predecessor registration and edge matching loops, remove
  the else gates so the entry-level FK loops run for all commands, not
  just those without a table. Add GetMappedConstraints guards to avoid
  double-processing FKs that are already handled by the table-level path.
- In CanCreateDependency, skip FKs where the other entity type is mapped
  to JSON. JSON-owned entities are stored inline and never have separate
  modification commands, so they cannot participate in inter-command
  dependency ordering. This prevents false cycles with entity splitting
  and JSON ownership.

Fixes dotnet#35978
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated no new comments.

@andrewraper-Sage andrewraper-Sage marked this pull request as ready for review April 16, 2026 07:57
@andrewraper-Sage
Copy link
Copy Markdown
Contributor Author

@AndriySvyryd I think I should have now address your comment and the concerns of Copilot. I am seeing a weird failure in the tests now. It appears that Microsoft.EntityFrameworkCore.Metadata.Conventions.ServicePropertyDiscoveryConventionTest.Finds_service_properties_in_hierarchy is failing, but this doesn't look like its related to any of the changes I've made. Can you advise please?

@AndriySvyryd
Copy link
Copy Markdown
Member

I think I should have now address your comment and the concerns of Copilot.

You still haven't restored the else blocks

It appears that Microsoft.EntityFrameworkCore.Metadata.Conventions.ServicePropertyDiscoveryConventionTest.Finds_service_properties_in_hierarchy is failing, but this doesn't look like its related to any of the changes I've made. Can you advise please?

That's unrelated, you can ignore this

@andrewraper-Sage
Copy link
Copy Markdown
Contributor Author

You still haven't restored the else blocks

I've restored these, and the tests have all passed now as well

Copy link
Copy Markdown
Member

@AndriySvyryd AndriySvyryd left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for your contribution!

@AndriySvyryd AndriySvyryd merged commit fe8e85f into dotnet:main Apr 17, 2026
15 checks passed
@andrewraper-Sage
Copy link
Copy Markdown
Contributor Author

Thanks for your contribution!

You’re welcome! Is there a chance this could be cherry picked and included in the next v10 patch release? @AndriySvyryd

@AndriySvyryd
Copy link
Copy Markdown
Member

You’re welcome! Is there a chance this could be cherry picked and included in the next v10 patch release?

That's unlikely, we haven't had that many reports considering that it was introduced in 9.0.0 and the fix is not trivial

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

EF Core Issue: Incorrect Save Order with TPC Inheritance

3 participants