Skip to content

Warn and fix identity conflict when owned entity has inconsistent data in DB#38596

Open
AndriySvyryd with Copilot wants to merge 6 commits into
mainfrom
copilot/fix-entity-loading-issue
Open

Warn and fix identity conflict when owned entity has inconsistent data in DB#38596
AndriySvyryd with Copilot wants to merge 6 commits into
mainfrom
copilot/fix-entity-loading-issue

Conversation

Copilot AI commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

When a row has NULL in a non-nullable column of an outer owned entity but non-NULL values in nested inner owned entity columns, EF Core silently materializes the outer as null while still tracking the inner entity. Any subsequent SaveChanges after replacing the outer owned entity then throws a misleading InvalidOperationException about an identity conflict.

Root cause

IncludeReference only handles the case where the owner entity is non-null. When the owner is null (due to the inconsistent data), the already-tracked inner entity remains in the state manager as an orphan, causing the identity conflict later.

Changes

  • IncludeReference fix (ShaperProcessingExpressionVisitor.ClientMethods.cs): Added an else if branch that detects a null owner with a non-null tracked owned entity on an ownership navigation. The caller detaches the orphaned entry (via the new QueryContext.TryGetEntry) and logs the appropriate warning.

  • QueryContext.TryGetEntry(object entity) (new [EntityFrameworkInternal] method): Looks up a tracked entity by object reference in the state manager. Used by the shaper to retrieve and detach orphaned owned entities.

  • CoreEventId.InconsistentOwnedDataWarning (new event, Warning level): Surfaced via CoreLoggerExtensions.InconsistentOwnedData (non-sensitive) and CoreLoggerExtensions.InconsistentOwnedDataSensitive (includes key values when sensitive data logging is enabled). Default behavior (with WarningBehavior.Throw) will throw on inconsistent data; users can configure to Log or Ignore.

  • API baseline (EFCore.baseline.json): Updated for the new public members.

  • Test (OwnedEntityQueryRelationalTestBase): Verifies that the warning is logged, Outer is null, and SaveChanges succeeds after replacing the owned entity with a valid instance.

// DB row: (Id=X, Outer_RequiredProperty=NULL, Outer_Inner_InnerProperty=42)
var root = await context.Set<RootEntity>().SingleAsync();
// root.Outer == null  ← was silently null before; now logs InconsistentOwnedDataWarning

root.Outer = new Outer { RequiredProperty = 1, Inner = new Inner { InnerProperty = 2 } };
await context.SaveChangesAsync(); // ← previously threw InvalidOperationException (identity conflict)

Copilot AI and others added 2 commits July 9, 2026 02:13
…hanges

Co-authored-by: AndriySvyryd <6539701+AndriySvyryd@users.noreply.github.com>
Co-authored-by: AndriySvyryd <6539701+AndriySvyryd@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix problem masking and unhelpful exception when loading entity Warn and fix identity conflict when owned entity has inconsistent data in DB Jul 9, 2026
Copilot AI requested a review from AndriySvyryd July 9, 2026 02:15
Comment thread src/EFCore/Query/QueryContext.cs Outdated
Copilot AI and others added 2 commits July 10, 2026 02:12
…sitive logging for InconsistentOwnedData

Co-authored-by: AndriySvyryd <6539701+AndriySvyryd@users.noreply.github.com>
…e message generator

Co-authored-by: AndriySvyryd <6539701+AndriySvyryd@users.noreply.github.com>
Comment thread src/EFCore/Diagnostics/CoreLoggerExtensions.cs Outdated
…ataWarning to match event ID

Co-authored-by: AndriySvyryd <6539701+AndriySvyryd@users.noreply.github.com>
Copilot AI requested a review from AndriySvyryd July 10, 2026 07:04
@AndriySvyryd AndriySvyryd marked this pull request as ready for review July 11, 2026 03:39
@AndriySvyryd AndriySvyryd requested a review from a team as a code owner July 11, 2026 03:39
Copilot AI review requested due to automatic review settings July 11, 2026 03:39

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

This PR addresses a tracking/identity-conflict edge case caused by inconsistent owned-entity data (outer owned entity materializes as null while an inner owned entity is still tracked), by detecting the condition during query materialization, detaching the orphaned owned entry, and emitting a dedicated warning.

Changes:

  • Adds a new query warning (CoreEventId.InconsistentOwnedDataWarning) with sensitive/non-sensitive logging via CoreLoggerExtensions and new CoreStrings resources.
  • Updates relational shaper IncludeReference to detect “null owner + tracked owned dependent” for ownership navigations, detach the orphan entry via a new QueryContext.TryGetEntry(object) helper, and log the warning.
  • Adds a relational spec test reproducing the inconsistent-data scenario and verifying warning + successful SaveChanges after replacing the owned instance.

Reviewed changes

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

Show a summary per file
File Description
test/EFCore.Tests/Diagnostics/CoreEventIdTest.cs Updates test stubs to support logging paths that access navigation target entity type.
test/EFCore.Relational.Specification.Tests/Query/OwnedEntityQueryRelationalTestBase.cs Adds coverage for inconsistent owned data leading to prior identity conflict on SaveChanges.
src/EFCore/Query/QueryContext.cs Adds internal API to locate a tracked entry by entity reference for shaper use.
src/EFCore/Properties/CoreStrings.resx Adds new localized warning messages (sensitive/non-sensitive).
src/EFCore/Properties/CoreStrings.Designer.cs Generated event-definition accessors for the new warning messages.
src/EFCore/EFCore.baseline.json Updates public API baseline for new event id and logger extension methods.
src/EFCore/Diagnostics/LoggingDefinitions.cs Adds logging definition slots for the new warning messages.
src/EFCore/Diagnostics/CoreLoggerExtensions.cs Adds logger extensions to emit the new warning (sensitive/non-sensitive).
src/EFCore/Diagnostics/CoreEventId.cs Introduces the new event id and documentation.
src/EFCore.Relational/Query/RelationalShapedQueryCompilingExpressionVisitor.ShaperProcessingExpressionVisitor.ClientMethods.cs Implements the detaching + warning behavior during include/reference fixup when the owner is null.
Files not reviewed (1)
  • src/EFCore/Properties/CoreStrings.Designer.cs: Generated file

using System.Runtime.CompilerServices;
using System.Text;
using System.Text.Json;
using Microsoft.EntityFrameworkCore.ChangeTracking.Internal;
Comment on lines +191 to +193
else if (trackingQuery
&& relatedEntity != null
&& navigation is INavigation { ForeignKey.IsOwnership: true })
Comment on lines +2988 to +2992
definition.Log(
diagnostics,
navigation.TargetEntityType.DisplayName(),
entry?.BuildCurrentValuesString(navigation.TargetEntityType.FindPrimaryKey()!.Properties) ?? "<unknown>",
navigation.DeclaringEntityType.ShortName() + "." + navigation.Name);
Comment on lines +350 to +358
/// <summary>
/// An owned entity was loaded, but the owning entity was null. This indicates inconsistent data in the database.
/// The owned entity will be ignored.
/// </summary>
/// <remarks>
/// This event is in the <see cref="DbLoggerCategory.Query" /> category.
/// </remarks>
public static readonly EventId InconsistentOwnedDataWarning
= MakeQueryId(Id.InconsistentOwnedDataWarning);
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.

Problem masking & unhelpful exception when loading entity with inconsistent data in owned entity columns

3 participants