From 874f3036e15c4c28324892be43cba24e8d10fd15 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 20 Feb 2026 00:32:55 +0000 Subject: [PATCH 1/5] Initial plan From 08abd8b3f3e905a625dfc1e985a18c70ec3c9ff7 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 20 Feb 2026 01:02:55 +0000 Subject: [PATCH 2/5] Add failing test for owned entity with default values in TPH with shared columns (#37525) Co-authored-by: AndriySvyryd <6539701+AndriySvyryd@users.noreply.github.com> --- .../Update/UpdatesRelationalTestBase.cs | 41 +++++++++++++++++++ .../TestModels/UpdatesModel/Nougat.cs | 35 ++++++++++++++++ .../TestModels/UpdatesModel/UpdatesContext.cs | 2 + .../Update/UpdatesTestBase.cs | 10 +++++ 4 files changed, 88 insertions(+) create mode 100644 test/EFCore.Specification.Tests/TestModels/UpdatesModel/Nougat.cs diff --git a/test/EFCore.Relational.Specification.Tests/Update/UpdatesRelationalTestBase.cs b/test/EFCore.Relational.Specification.Tests/Update/UpdatesRelationalTestBase.cs index 161445deb85..b6ddbbf7dbd 100644 --- a/test/EFCore.Relational.Specification.Tests/Update/UpdatesRelationalTestBase.cs +++ b/test/EFCore.Relational.Specification.Tests/Update/UpdatesRelationalTestBase.cs @@ -260,6 +260,30 @@ public virtual Task Update_non_indexed_values() }); } + [ConditionalTheory, InlineData(false), InlineData(true)] // Issue #37525 + public virtual async Task Can_save_owned_entity_with_default_values_in_TPH_with_shared_columns(bool async) + => await ExecuteWithStrategyInTransactionAsync( + async context => + { + var entity = new CrunchyNougat { Name = "Test" }; + context.Add(entity); + _ = async ? await context.SaveChangesAsync() : context.SaveChanges(); + }, + async context => + { + var entity = await context.Set().SingleAsync(); + Assert.Null(entity.Filling); + entity.Filling = new NougatFilling(); + _ = async ? await context.SaveChangesAsync() : context.SaveChanges(); + }, + async context => + { + var entity = await context.Set().SingleAsync(); + Assert.NotNull(entity.Filling); + Assert.Equal(NougatFillingKind.Unknown, entity.Filling.Kind); + Assert.False(entity.Filling.IsFresh); + }); + [ConditionalFact] public abstract void Identifiers_are_generated_correctly(); @@ -301,6 +325,23 @@ protected override void OnModelCreating(ModelBuilder modelBuilder, DbContext con .HasColumnName("ZipCode"); }); + modelBuilder.Entity(b => + { + b.OwnsOne(e => e.Filling, ob => + { + ob.Property(o => o.Kind).HasColumnName("FillingKind"); + ob.Property(o => o.IsFresh).HasColumnName("FillingIsFresh"); + }); + }); + modelBuilder.Entity(b => + { + b.OwnsOne(e => e.Filling, ob => + { + ob.Property(o => o.Kind).HasColumnName("FillingKind"); + ob.Property(o => o.IsFresh).HasColumnName("FillingIsFresh"); + }); + }); + modelBuilder .Entity< LoginEntityTypeWithAnExtremelyLongAndOverlyConvolutedNameThatIsUsedToVerifyThatTheStoreIdentifierGenerationLengthLimitIsWorkingCorrectlyDetails diff --git a/test/EFCore.Specification.Tests/TestModels/UpdatesModel/Nougat.cs b/test/EFCore.Specification.Tests/TestModels/UpdatesModel/Nougat.cs new file mode 100644 index 00000000000..0c64ac27d73 --- /dev/null +++ b/test/EFCore.Specification.Tests/TestModels/UpdatesModel/Nougat.cs @@ -0,0 +1,35 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace Microsoft.EntityFrameworkCore.TestModels.UpdatesModel; + +#nullable disable + +public abstract class Nougat +{ + public int Id { get; set; } + public string Name { get; set; } +} + +public class CrunchyNougat : Nougat +{ + public NougatFilling Filling { get; set; } +} + +public class SoftNougat : Nougat +{ + public NougatFilling Filling { get; set; } +} + +public class NougatFilling +{ + public NougatFillingKind Kind { get; set; } + public bool IsFresh { get; set; } +} + +public enum NougatFillingKind +{ + Unknown = 0, + Peanut = 1, + Almond = 2, +} diff --git a/test/EFCore.Specification.Tests/TestModels/UpdatesModel/UpdatesContext.cs b/test/EFCore.Specification.Tests/TestModels/UpdatesModel/UpdatesContext.cs index 7213ae7709c..51c261b3f54 100644 --- a/test/EFCore.Specification.Tests/TestModels/UpdatesModel/UpdatesContext.cs +++ b/test/EFCore.Specification.Tests/TestModels/UpdatesModel/UpdatesContext.cs @@ -15,6 +15,8 @@ public class UpdatesContext(DbContextOptions options) : PoolableDbContext(option public DbSet ProductTable { get; set; } = null!; public DbSet ProductTableView { get; set; } = null!; public DbSet Trotters { get; set; } = null!; + public DbSet CrunchyNougats { get; set; } = null!; + public DbSet SoftNougats { get; set; } = null!; public static Task SeedAsync(UpdatesContext context) { diff --git a/test/EFCore.Specification.Tests/Update/UpdatesTestBase.cs b/test/EFCore.Specification.Tests/Update/UpdatesTestBase.cs index 2ed28894753..8ef8adf2314 100644 --- a/test/EFCore.Specification.Tests/Update/UpdatesTestBase.cs +++ b/test/EFCore.Specification.Tests/Update/UpdatesTestBase.cs @@ -1042,6 +1042,16 @@ protected override void OnModelCreating(ModelBuilder modelBuilder, DbContext con modelBuilder.Entity().HasOne().WithOne(x => x.Obscurer).HasForeignKey(e => e.LiftId); modelBuilder.Entity(); modelBuilder.Entity(); + + modelBuilder.Entity(); + modelBuilder.Entity(b => + { + b.OwnsOne(e => e.Filling); + }); + modelBuilder.Entity(b => + { + b.OwnsOne(e => e.Filling); + }); } protected override Task SeedAsync(UpdatesContext context) From c31e13c8728028a0a58a4874588b7656ce43dc3e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 20 Feb 2026 01:07:45 +0000 Subject: [PATCH 3/5] Fix ColumnValuePropagator.TryPropagate to write sentinel values from Added entries (#37525) Co-authored-by: AndriySvyryd <6539701+AndriySvyryd@users.noreply.github.com> --- src/EFCore.Relational/Update/ModificationCommand.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/EFCore.Relational/Update/ModificationCommand.cs b/src/EFCore.Relational/Update/ModificationCommand.cs index 62d6596ecf1..8b7de56be0c 100644 --- a/src/EFCore.Relational/Update/ModificationCommand.cs +++ b/src/EFCore.Relational/Update/ModificationCommand.cs @@ -1256,7 +1256,10 @@ public bool TryPropagate(IColumnMappingBase mapping, IUpdateEntry entry) && ((!_originalValueInitialized && property.GetValueComparer().Equals( Update.ColumnModification.GetCurrentValue(entry, property), - property.Sentinel)) + property.Sentinel) + && !mapping.Column.ProviderValueComparer.Equals( + _currentValue, + Update.ColumnModification.GetCurrentProviderValue(entry, property))) || (_originalValueInitialized && mapping.Column.ProviderValueComparer.Equals( Update.ColumnModification.GetCurrentProviderValue(entry, property), From fb4099b8c871cfab3971dbbd0d1909467d7d6cce Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 20 Feb 2026 03:52:47 +0000 Subject: [PATCH 4/5] Add HasConversion() to NougatFilling.Kind to match repro pattern (#37525) Co-authored-by: AndriySvyryd <6539701+AndriySvyryd@users.noreply.github.com> --- .../Update/UpdatesTestBase.cs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/test/EFCore.Specification.Tests/Update/UpdatesTestBase.cs b/test/EFCore.Specification.Tests/Update/UpdatesTestBase.cs index 8ef8adf2314..45a30aee83b 100644 --- a/test/EFCore.Specification.Tests/Update/UpdatesTestBase.cs +++ b/test/EFCore.Specification.Tests/Update/UpdatesTestBase.cs @@ -1046,11 +1046,17 @@ protected override void OnModelCreating(ModelBuilder modelBuilder, DbContext con modelBuilder.Entity(); modelBuilder.Entity(b => { - b.OwnsOne(e => e.Filling); + b.OwnsOne(e => e.Filling, ob => + { + ob.Property(o => o.Kind).HasConversion(); + }); }); modelBuilder.Entity(b => { - b.OwnsOne(e => e.Filling); + b.OwnsOne(e => e.Filling, ob => + { + ob.Property(o => o.Kind).HasConversion(); + }); }); } From ae3f4d22e61b9beccca0f90cc639184f92216247 Mon Sep 17 00:00:00 2001 From: Andriy Svyryd Date: Mon, 23 Feb 2026 13:00:19 -0800 Subject: [PATCH 5/5] Add quirk mode --- src/EFCore.Relational/Update/ModificationCommand.cs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/EFCore.Relational/Update/ModificationCommand.cs b/src/EFCore.Relational/Update/ModificationCommand.cs index 8b7de56be0c..87d82de76a8 100644 --- a/src/EFCore.Relational/Update/ModificationCommand.cs +++ b/src/EFCore.Relational/Update/ModificationCommand.cs @@ -40,6 +40,9 @@ public class ModificationCommand : IModificationCommand, INonTrackedModification private static readonly bool UseOldBehavior37373 = AppContext.TryGetSwitch("Microsoft.EntityFrameworkCore.Issue37373", out var enabled) && enabled; + private static readonly bool UseOldBehavior37525 = + AppContext.TryGetSwitch("Microsoft.EntityFrameworkCore.Issue37525", out var enabled37525) && enabled37525; + /// /// Initializes a new instance. /// @@ -1257,9 +1260,10 @@ public bool TryPropagate(IColumnMappingBase mapping, IUpdateEntry entry) && property.GetValueComparer().Equals( Update.ColumnModification.GetCurrentValue(entry, property), property.Sentinel) - && !mapping.Column.ProviderValueComparer.Equals( - _currentValue, - Update.ColumnModification.GetCurrentProviderValue(entry, property))) + && (UseOldBehavior37525 + || !mapping.Column.ProviderValueComparer.Equals( + _currentValue, + Update.ColumnModification.GetCurrentProviderValue(entry, property)))) || (_originalValueInitialized && mapping.Column.ProviderValueComparer.Equals( Update.ColumnModification.GetCurrentProviderValue(entry, property),