diff --git a/src/EFCore.Relational/Update/ModificationCommand.cs b/src/EFCore.Relational/Update/ModificationCommand.cs
index 62d6596ecf1..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.
///
@@ -1256,7 +1259,11 @@ public bool TryPropagate(IColumnMappingBase mapping, IUpdateEntry entry)
&& ((!_originalValueInitialized
&& property.GetValueComparer().Equals(
Update.ColumnModification.GetCurrentValue(entry, property),
- property.Sentinel))
+ property.Sentinel)
+ && (UseOldBehavior37525
+ || !mapping.Column.ProviderValueComparer.Equals(
+ _currentValue,
+ Update.ColumnModification.GetCurrentProviderValue(entry, property))))
|| (_originalValueInitialized
&& mapping.Column.ProviderValueComparer.Equals(
Update.ColumnModification.GetCurrentProviderValue(entry, property),
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..45a30aee83b 100644
--- a/test/EFCore.Specification.Tests/Update/UpdatesTestBase.cs
+++ b/test/EFCore.Specification.Tests/Update/UpdatesTestBase.cs
@@ -1042,6 +1042,22 @@ 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, ob =>
+ {
+ ob.Property(o => o.Kind).HasConversion();
+ });
+ });
+ modelBuilder.Entity(b =>
+ {
+ b.OwnsOne(e => e.Filling, ob =>
+ {
+ ob.Property(o => o.Kind).HasConversion();
+ });
+ });
}
protected override Task SeedAsync(UpdatesContext context)