From 4ab89888968b724d9ddfd5152c1ff7a5f004ade1 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 2 Mar 2026 19:26:52 +0000 Subject: [PATCH 1/8] Initial plan From ac724a1f2ed2d0caab8662e97a61a5e52d419acf Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 2 Mar 2026 19:41:08 +0000 Subject: [PATCH 2/8] Add test and fix for TPH inheritance with owned JSON type NRE when replacing 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 <6539701+AndriySvyryd@users.noreply.github.com> --- .../Update/ModificationCommand.cs | 7 ++++ .../Update/JsonUpdateFixtureBase.cs | 34 +++++++++++++++++++ .../Update/JsonUpdateTestBase.cs | 28 +++++++++++++++ .../TestModels/JsonQuery/JsonEntityTphItem.cs | 13 +++++++ .../JsonQuery/JsonEntityTphItemAttribute.cs | 12 +++++++ .../JsonQuery/JsonEntityTphLocaleAttribute.cs | 11 ++++++ .../JsonQuery/JsonEntityTphStringAttribute.cs | 11 ++++++ .../JsonQuery/JsonOwnedTphLocaleValue.cs | 11 ++++++ .../JsonQuery/JsonOwnedTphLocaleValueEntry.cs | 12 +++++++ .../TestModels/JsonQuery/JsonQueryContext.cs | 1 + .../TestModels/JsonQuery/JsonQueryData.cs | 31 +++++++++++++++++ .../JsonUpdateJsonTypeSqlServerFixture.cs | 5 +++ .../Update/JsonUpdateJsonTypeSqlServerTest.cs | 5 +++ 13 files changed, 181 insertions(+) create mode 100644 test/EFCore.Specification.Tests/TestModels/JsonQuery/JsonEntityTphItem.cs create mode 100644 test/EFCore.Specification.Tests/TestModels/JsonQuery/JsonEntityTphItemAttribute.cs create mode 100644 test/EFCore.Specification.Tests/TestModels/JsonQuery/JsonEntityTphLocaleAttribute.cs create mode 100644 test/EFCore.Specification.Tests/TestModels/JsonQuery/JsonEntityTphStringAttribute.cs create mode 100644 test/EFCore.Specification.Tests/TestModels/JsonQuery/JsonOwnedTphLocaleValue.cs create mode 100644 test/EFCore.Specification.Tests/TestModels/JsonQuery/JsonOwnedTphLocaleValueEntry.cs diff --git a/src/EFCore.Relational/Update/ModificationCommand.cs b/src/EFCore.Relational/Update/ModificationCommand.cs index 8361516677a..4fdf24f3009 100644 --- a/src/EFCore.Relational/Update/ModificationCommand.cs +++ b/src/EFCore.Relational/Update/ModificationCommand.cs @@ -594,6 +594,13 @@ void HandleSharedColumns( (InternalEntityEntry)currentEntry, currentOwnership)!; #pragma warning restore EF1001 // Internal EF Core API usage. + // principal entity was replaced with a different derived type (e.g. TPH), + // no need to do any json-specific processing + if (currentEntry == null) + { + return null; + } + if (processedEntries.Contains(currentEntry)) { return null; diff --git a/test/EFCore.Relational.Specification.Tests/Update/JsonUpdateFixtureBase.cs b/test/EFCore.Relational.Specification.Tests/Update/JsonUpdateFixtureBase.cs index 58e37c1491b..12882510088 100644 --- a/test/EFCore.Relational.Specification.Tests/Update/JsonUpdateFixtureBase.cs +++ b/test/EFCore.Relational.Specification.Tests/Update/JsonUpdateFixtureBase.cs @@ -200,6 +200,38 @@ protected override void OnModelCreating(ModelBuilder modelBuilder, DbContext con b.Property(x => x.Name); }); + modelBuilder.Entity(b => + { + b.Property(x => x.Id).ValueGeneratedNever(); + b.HasMany(x => x.Attributes).WithOne().HasForeignKey(x => x.JsonEntityTphItemId); + }); + + modelBuilder.Entity(b => + { + b.HasKey(x => new { x.JsonEntityTphItemId, x.Key }); + b.HasDiscriminator("Discriminator") + .HasValue("string") + .HasValue("locale-value"); + }); + + modelBuilder.Entity(b => + { + b.Property(x => x.Value).HasColumnName("StringValue"); + }); + + modelBuilder.Entity(b => + { + b.OwnsOne(x => x.Value, bc => + { + bc.ToJson("LocaleValue"); + bc.OwnsMany(x => x.Entries, v => + { + v.Property(x => x.Locale).IsRequired(); + v.Property(x => x.Value); + }); + }); + }); + base.OnModelCreating(modelBuilder, context); } @@ -209,11 +241,13 @@ protected override Task SeedAsync(JsonQueryContext context) var jsonEntitiesInheritance = JsonQueryData.CreateJsonEntitiesInheritance(); var jsonEntitiesAllTypes = JsonQueryData.CreateJsonEntitiesAllTypes(); var jsonEntitiesConverters = JsonQueryData.CreateJsonEntitiesConverters(); + var jsonEntitiesTphItems = JsonQueryData.CreateJsonEntitiesTphItems(); context.JsonEntitiesBasic.AddRange(jsonEntitiesBasic); context.JsonEntitiesInheritance.AddRange(jsonEntitiesInheritance); context.JsonEntitiesAllTypes.AddRange(jsonEntitiesAllTypes); context.JsonEntitiesConverters.AddRange(jsonEntitiesConverters); + context.JsonEntitiesTphItems.AddRange(jsonEntitiesTphItems); return context.SaveChangesAsync(); } diff --git a/test/EFCore.Relational.Specification.Tests/Update/JsonUpdateTestBase.cs b/test/EFCore.Relational.Specification.Tests/Update/JsonUpdateTestBase.cs index 2dd1a172555..95eece37760 100644 --- a/test/EFCore.Relational.Specification.Tests/Update/JsonUpdateTestBase.cs +++ b/test/EFCore.Relational.Specification.Tests/Update/JsonUpdateTestBase.cs @@ -3732,6 +3732,34 @@ public virtual Task Replace_json_reference_root_preserves_nested_owned_entities_ Assert.NotNull(result.OwnedReferenceRoot.OwnedReferenceBranch.OwnedReferenceLeaf); }); + [ConditionalFact] + public virtual Task Replace_derived_entity_with_json_to_different_derived_type_with_same_key() + => TestHelpers.ExecuteWithStrategyInTransactionAsync( + CreateContext, + UseTransaction, + async context => + { + var item = await context.JsonEntitiesTphItems.Include(x => x.Attributes).SingleAsync(); + + item.Attributes.RemoveAll(attr => attr.Key == "TextValue"); + item.Attributes.Add(new JsonEntityTphStringAttribute + { + Key = "TextValue", + Value = "World" + }); + + ClearLog(); + await context.SaveChangesAsync(); + }, + async context => + { + var item = await context.JsonEntitiesTphItems.Include(x => x.Attributes).SingleAsync(); + var attribute = Assert.Single(item.Attributes); + var stringAttribute = Assert.IsType(attribute); + Assert.Equal("TextValue", stringAttribute.Key); + Assert.Equal("World", stringAttribute.Value); + }); + public void UseTransaction(DatabaseFacade facade, IDbContextTransaction transaction) => facade.UseTransaction(transaction.GetDbTransaction()); diff --git a/test/EFCore.Specification.Tests/TestModels/JsonQuery/JsonEntityTphItem.cs b/test/EFCore.Specification.Tests/TestModels/JsonQuery/JsonEntityTphItem.cs new file mode 100644 index 00000000000..87841e78099 --- /dev/null +++ b/test/EFCore.Specification.Tests/TestModels/JsonQuery/JsonEntityTphItem.cs @@ -0,0 +1,13 @@ +// 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.JsonQuery; + +#nullable disable + +public class JsonEntityTphItem +{ + public int Id { get; set; } + public string Name { get; set; } + public List Attributes { get; set; } = []; +} diff --git a/test/EFCore.Specification.Tests/TestModels/JsonQuery/JsonEntityTphItemAttribute.cs b/test/EFCore.Specification.Tests/TestModels/JsonQuery/JsonEntityTphItemAttribute.cs new file mode 100644 index 00000000000..c35f6dee5c0 --- /dev/null +++ b/test/EFCore.Specification.Tests/TestModels/JsonQuery/JsonEntityTphItemAttribute.cs @@ -0,0 +1,12 @@ +// 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.JsonQuery; + +#nullable disable + +public abstract class JsonEntityTphItemAttribute +{ + public int JsonEntityTphItemId { get; set; } + public string Key { get; set; } +} diff --git a/test/EFCore.Specification.Tests/TestModels/JsonQuery/JsonEntityTphLocaleAttribute.cs b/test/EFCore.Specification.Tests/TestModels/JsonQuery/JsonEntityTphLocaleAttribute.cs new file mode 100644 index 00000000000..e855780065f --- /dev/null +++ b/test/EFCore.Specification.Tests/TestModels/JsonQuery/JsonEntityTphLocaleAttribute.cs @@ -0,0 +1,11 @@ +// 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.JsonQuery; + +#nullable disable + +public class JsonEntityTphLocaleAttribute : JsonEntityTphItemAttribute +{ + public JsonOwnedTphLocaleValue Value { get; set; } +} diff --git a/test/EFCore.Specification.Tests/TestModels/JsonQuery/JsonEntityTphStringAttribute.cs b/test/EFCore.Specification.Tests/TestModels/JsonQuery/JsonEntityTphStringAttribute.cs new file mode 100644 index 00000000000..866cb8b1335 --- /dev/null +++ b/test/EFCore.Specification.Tests/TestModels/JsonQuery/JsonEntityTphStringAttribute.cs @@ -0,0 +1,11 @@ +// 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.JsonQuery; + +#nullable disable + +public class JsonEntityTphStringAttribute : JsonEntityTphItemAttribute +{ + public string Value { get; set; } +} diff --git a/test/EFCore.Specification.Tests/TestModels/JsonQuery/JsonOwnedTphLocaleValue.cs b/test/EFCore.Specification.Tests/TestModels/JsonQuery/JsonOwnedTphLocaleValue.cs new file mode 100644 index 00000000000..b08c0180497 --- /dev/null +++ b/test/EFCore.Specification.Tests/TestModels/JsonQuery/JsonOwnedTphLocaleValue.cs @@ -0,0 +1,11 @@ +// 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.JsonQuery; + +#nullable disable + +public class JsonOwnedTphLocaleValue +{ + public List Entries { get; set; } = []; +} diff --git a/test/EFCore.Specification.Tests/TestModels/JsonQuery/JsonOwnedTphLocaleValueEntry.cs b/test/EFCore.Specification.Tests/TestModels/JsonQuery/JsonOwnedTphLocaleValueEntry.cs new file mode 100644 index 00000000000..8ac065a4989 --- /dev/null +++ b/test/EFCore.Specification.Tests/TestModels/JsonQuery/JsonOwnedTphLocaleValueEntry.cs @@ -0,0 +1,12 @@ +// 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.JsonQuery; + +#nullable disable + +public class JsonOwnedTphLocaleValueEntry +{ + public string Locale { get; set; } + public string Value { get; set; } +} diff --git a/test/EFCore.Specification.Tests/TestModels/JsonQuery/JsonQueryContext.cs b/test/EFCore.Specification.Tests/TestModels/JsonQuery/JsonQueryContext.cs index b6010b6182f..b0eb3c84bb4 100644 --- a/test/EFCore.Specification.Tests/TestModels/JsonQuery/JsonQueryContext.cs +++ b/test/EFCore.Specification.Tests/TestModels/JsonQuery/JsonQueryContext.cs @@ -16,6 +16,7 @@ public class JsonQueryContext(DbContextOptions options) : DbContext(options) public DbSet JsonEntitiesInheritance { get; set; } public DbSet JsonEntitiesAllTypes { get; set; } public DbSet JsonEntitiesConverters { get; set; } + public DbSet JsonEntitiesTphItems { get; set; } public static Task SeedAsync(JsonQueryContext context) { diff --git a/test/EFCore.Specification.Tests/TestModels/JsonQuery/JsonQueryData.cs b/test/EFCore.Specification.Tests/TestModels/JsonQuery/JsonQueryData.cs index 6a65549b664..3e9f46e92ce 100644 --- a/test/EFCore.Specification.Tests/TestModels/JsonQuery/JsonQueryData.cs +++ b/test/EFCore.Specification.Tests/TestModels/JsonQuery/JsonQueryData.cs @@ -22,6 +22,7 @@ public JsonQueryData() JsonEntitiesInheritance = CreateJsonEntitiesInheritance(); JsonEntitiesAllTypes = CreateJsonEntitiesAllTypes(); JsonEntitiesConverters = CreateJsonEntitiesConverters(); + JsonEntitiesTphItems = CreateJsonEntitiesTphItems(); } public IReadOnlyList EntitiesBasic { get; } @@ -33,6 +34,7 @@ public JsonQueryData() public IReadOnlyList JsonEntitiesInheritance { get; set; } public IReadOnlyList JsonEntitiesAllTypes { get; set; } public IReadOnlyList JsonEntitiesConverters { get; set; } + public IReadOnlyList JsonEntitiesTphItems { get; set; } public static IReadOnlyList CreateJsonEntitiesBasic() { @@ -1470,6 +1472,30 @@ public static IReadOnlyList CreateJsonEntitiesConverters() }; } + public static IReadOnlyList CreateJsonEntitiesTphItems() + => new List + { + new() + { + Id = 1, + Name = "Product 1", + Attributes = + [ + new JsonEntityTphLocaleAttribute + { + Key = "TextValue", + Value = new JsonOwnedTphLocaleValue + { + Entries = + [ + new JsonOwnedTphLocaleValueEntry { Locale = "en-US", Value = "Hello" } + ] + } + } + ] + } + }; + public IQueryable Set() where TEntity : class { @@ -1523,6 +1549,11 @@ public IQueryable Set() return (IQueryable)JsonEntitiesBasicForCollection.AsQueryable(); } + if (typeof(TEntity) == typeof(JsonEntityTphItem)) + { + return (IQueryable)JsonEntitiesTphItems.AsQueryable(); + } + throw new InvalidOperationException("Invalid entity type: " + typeof(TEntity)); } } diff --git a/test/EFCore.SqlServer.FunctionalTests/Update/JsonUpdateJsonTypeSqlServerFixture.cs b/test/EFCore.SqlServer.FunctionalTests/Update/JsonUpdateJsonTypeSqlServerFixture.cs index bdbcae78afa..26c1b3bc5bb 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Update/JsonUpdateJsonTypeSqlServerFixture.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Update/JsonUpdateJsonTypeSqlServerFixture.cs @@ -68,5 +68,10 @@ protected override void OnModelCreating(ModelBuilder modelBuilder, DbContext con }); modelBuilder.Entity().OwnsOne(x => x.Reference).ToJson().HasColumnType("json"); + + modelBuilder.Entity(b => + { + b.OwnsOne(x => x.Value).ToJson().HasColumnType("json"); + }); } } diff --git a/test/EFCore.SqlServer.FunctionalTests/Update/JsonUpdateJsonTypeSqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Update/JsonUpdateJsonTypeSqlServerTest.cs index eeec57d6bea..dd1bf78c384 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Update/JsonUpdateJsonTypeSqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Update/JsonUpdateJsonTypeSqlServerTest.cs @@ -3299,6 +3299,11 @@ FROM [JsonEntitiesBasic] AS [j] protected override void ClearLog() => Fixture.TestSqlLoggerFactory.Clear(); + public override async Task Replace_derived_entity_with_json_to_different_derived_type_with_same_key() + { + await base.Replace_derived_entity_with_json_to_different_derived_type_with_same_key(); + } + private void AssertSql(params string[] expected) => Fixture.TestSqlLoggerFactory.AssertBaseline(expected); } From 64a9f419ccdd3163310e49a8423d5cd51bfd3d35 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 2 Mar 2026 19:45:04 +0000 Subject: [PATCH 3/8] Address code review: remove collection initializers to match existing test model conventions Co-authored-by: AndriySvyryd <6539701+AndriySvyryd@users.noreply.github.com> --- .../TestModels/JsonQuery/JsonEntityTphItem.cs | 2 +- .../TestModels/JsonQuery/JsonOwnedTphLocaleValue.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/EFCore.Specification.Tests/TestModels/JsonQuery/JsonEntityTphItem.cs b/test/EFCore.Specification.Tests/TestModels/JsonQuery/JsonEntityTphItem.cs index 87841e78099..50d62760365 100644 --- a/test/EFCore.Specification.Tests/TestModels/JsonQuery/JsonEntityTphItem.cs +++ b/test/EFCore.Specification.Tests/TestModels/JsonQuery/JsonEntityTphItem.cs @@ -9,5 +9,5 @@ public class JsonEntityTphItem { public int Id { get; set; } public string Name { get; set; } - public List Attributes { get; set; } = []; + public List Attributes { get; set; } } diff --git a/test/EFCore.Specification.Tests/TestModels/JsonQuery/JsonOwnedTphLocaleValue.cs b/test/EFCore.Specification.Tests/TestModels/JsonQuery/JsonOwnedTphLocaleValue.cs index b08c0180497..76b3c3a2a86 100644 --- a/test/EFCore.Specification.Tests/TestModels/JsonQuery/JsonOwnedTphLocaleValue.cs +++ b/test/EFCore.Specification.Tests/TestModels/JsonQuery/JsonOwnedTphLocaleValue.cs @@ -7,5 +7,5 @@ namespace Microsoft.EntityFrameworkCore.TestModels.JsonQuery; public class JsonOwnedTphLocaleValue { - public List Entries { get; set; } = []; + public List Entries { get; set; } } From 315fad05e6935cb8edea1fbc5c2cd1f4f21eab04 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 2 Mar 2026 22:04:42 +0000 Subject: [PATCH 4/8] Merge null check with processedEntries.Contains check per review feedback Co-authored-by: AndriySvyryd <6539701+AndriySvyryd@users.noreply.github.com> --- src/EFCore.Relational/Update/ModificationCommand.cs | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/src/EFCore.Relational/Update/ModificationCommand.cs b/src/EFCore.Relational/Update/ModificationCommand.cs index 4fdf24f3009..2401d350f7a 100644 --- a/src/EFCore.Relational/Update/ModificationCommand.cs +++ b/src/EFCore.Relational/Update/ModificationCommand.cs @@ -594,14 +594,7 @@ void HandleSharedColumns( (InternalEntityEntry)currentEntry, currentOwnership)!; #pragma warning restore EF1001 // Internal EF Core API usage. - // principal entity was replaced with a different derived type (e.g. TPH), - // no need to do any json-specific processing - if (currentEntry == null) - { - return null; - } - - if (processedEntries.Contains(currentEntry)) + if (currentEntry == null || processedEntries.Contains(currentEntry)) { return null; } From b73c74350a01a45a3be0f85affb80183d376d480 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 2 Mar 2026 22:23:45 +0000 Subject: [PATCH 5/8] Add TPH model configuration to JsonQueryFixtureBase and JsonQueryRelationalFixture Co-authored-by: AndriySvyryd <6539701+AndriySvyryd@users.noreply.github.com> --- .../Query/JsonQueryRelationalFixture.cs | 18 ++++++++++++++++++ .../Query/JsonQueryFixtureBase.cs | 14 ++++++++++++++ .../TestModels/JsonQuery/JsonQueryContext.cs | 4 ++++ 3 files changed, 36 insertions(+) diff --git a/test/EFCore.Relational.Specification.Tests/Query/JsonQueryRelationalFixture.cs b/test/EFCore.Relational.Specification.Tests/Query/JsonQueryRelationalFixture.cs index b69eec919fe..9d7182b2b27 100644 --- a/test/EFCore.Relational.Specification.Tests/Query/JsonQueryRelationalFixture.cs +++ b/test/EFCore.Relational.Specification.Tests/Query/JsonQueryRelationalFixture.cs @@ -59,5 +59,23 @@ protected override void OnModelCreating(ModelBuilder modelBuilder, DbContext con modelBuilder.Entity().OwnsMany(x => x.Collection).ToJson(); modelBuilder.Entity().OwnsOne(x => x.Reference).ToJson(); + + modelBuilder.Entity(b => + { + b.Property(x => x.Value).HasColumnName("StringValue"); + }); + + modelBuilder.Entity(b => + { + b.OwnsOne(x => x.Value, bc => + { + bc.ToJson("LocaleValue"); + bc.OwnsMany(x => x.Entries, v => + { + v.Property(x => x.Locale).IsRequired(); + v.Property(x => x.Value); + }); + }); + }); } } diff --git a/test/EFCore.Specification.Tests/Query/JsonQueryFixtureBase.cs b/test/EFCore.Specification.Tests/Query/JsonQueryFixtureBase.cs index e3dba32f797..c14abe1ff82 100644 --- a/test/EFCore.Specification.Tests/Query/JsonQueryFixtureBase.cs +++ b/test/EFCore.Specification.Tests/Query/JsonQueryFixtureBase.cs @@ -644,6 +644,20 @@ protected override void OnModelCreating(ModelBuilder modelBuilder, DbContext con x => x == "Y" ? true : false, x => x == true ? "Y" : "N")); }); + + modelBuilder.Entity(b => + { + b.Property(x => x.Id).ValueGeneratedNever(); + b.HasMany(x => x.Attributes).WithOne().HasForeignKey(x => x.JsonEntityTphItemId); + }); + + modelBuilder.Entity(b => + { + b.HasKey(x => new { x.JsonEntityTphItemId, x.Key }); + b.HasDiscriminator("Discriminator") + .HasValue("string") + .HasValue("locale-value"); + }); } protected override string StoreName diff --git a/test/EFCore.Specification.Tests/TestModels/JsonQuery/JsonQueryContext.cs b/test/EFCore.Specification.Tests/TestModels/JsonQuery/JsonQueryContext.cs index b0eb3c84bb4..ff3d2526615 100644 --- a/test/EFCore.Specification.Tests/TestModels/JsonQuery/JsonQueryContext.cs +++ b/test/EFCore.Specification.Tests/TestModels/JsonQuery/JsonQueryContext.cs @@ -41,6 +41,10 @@ public static Task SeedAsync(JsonQueryContext context) context.JsonEntitiesInheritance.AddRange(jsonEntitiesInheritance); context.JsonEntitiesAllTypes.AddRange(jsonEntitiesAllTypes); context.JsonEntitiesConverters.AddRange(jsonEntitiesConverters); + + var jsonEntitiesTphItems = JsonQueryData.CreateJsonEntitiesTphItems(); + context.JsonEntitiesTphItems.AddRange(jsonEntitiesTphItems); + return context.SaveChangesAsync(); } } From f1013f5b47b32dc1a39d66fc73610413e96b4c3f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 3 Mar 2026 00:01:58 +0000 Subject: [PATCH 6/8] Rewrite test to use existing JsonEntityInheritance hierarchy instead of new Tph classes Co-authored-by: AndriySvyryd <6539701+AndriySvyryd@users.noreply.github.com> --- .../Query/JsonQueryRelationalFixture.cs | 18 ---------- .../Update/JsonUpdateFixtureBase.cs | 34 ------------------- .../Update/JsonUpdateTestBase.cs | 32 ++++++++++------- .../Query/JsonQueryFixtureBase.cs | 14 -------- .../TestModels/JsonQuery/JsonEntityTphItem.cs | 13 ------- .../JsonQuery/JsonEntityTphItemAttribute.cs | 12 ------- .../JsonQuery/JsonEntityTphLocaleAttribute.cs | 11 ------ .../JsonQuery/JsonEntityTphStringAttribute.cs | 11 ------ .../JsonQuery/JsonOwnedTphLocaleValue.cs | 11 ------ .../JsonQuery/JsonOwnedTphLocaleValueEntry.cs | 12 ------- .../TestModels/JsonQuery/JsonQueryContext.cs | 5 --- .../TestModels/JsonQuery/JsonQueryData.cs | 31 ----------------- .../JsonUpdateJsonTypeSqlServerFixture.cs | 5 --- .../Update/JsonUpdateJsonTypeSqlServerTest.cs | 4 +-- 14 files changed, 22 insertions(+), 191 deletions(-) delete mode 100644 test/EFCore.Specification.Tests/TestModels/JsonQuery/JsonEntityTphItem.cs delete mode 100644 test/EFCore.Specification.Tests/TestModels/JsonQuery/JsonEntityTphItemAttribute.cs delete mode 100644 test/EFCore.Specification.Tests/TestModels/JsonQuery/JsonEntityTphLocaleAttribute.cs delete mode 100644 test/EFCore.Specification.Tests/TestModels/JsonQuery/JsonEntityTphStringAttribute.cs delete mode 100644 test/EFCore.Specification.Tests/TestModels/JsonQuery/JsonOwnedTphLocaleValue.cs delete mode 100644 test/EFCore.Specification.Tests/TestModels/JsonQuery/JsonOwnedTphLocaleValueEntry.cs diff --git a/test/EFCore.Relational.Specification.Tests/Query/JsonQueryRelationalFixture.cs b/test/EFCore.Relational.Specification.Tests/Query/JsonQueryRelationalFixture.cs index 9d7182b2b27..b69eec919fe 100644 --- a/test/EFCore.Relational.Specification.Tests/Query/JsonQueryRelationalFixture.cs +++ b/test/EFCore.Relational.Specification.Tests/Query/JsonQueryRelationalFixture.cs @@ -59,23 +59,5 @@ protected override void OnModelCreating(ModelBuilder modelBuilder, DbContext con modelBuilder.Entity().OwnsMany(x => x.Collection).ToJson(); modelBuilder.Entity().OwnsOne(x => x.Reference).ToJson(); - - modelBuilder.Entity(b => - { - b.Property(x => x.Value).HasColumnName("StringValue"); - }); - - modelBuilder.Entity(b => - { - b.OwnsOne(x => x.Value, bc => - { - bc.ToJson("LocaleValue"); - bc.OwnsMany(x => x.Entries, v => - { - v.Property(x => x.Locale).IsRequired(); - v.Property(x => x.Value); - }); - }); - }); } } diff --git a/test/EFCore.Relational.Specification.Tests/Update/JsonUpdateFixtureBase.cs b/test/EFCore.Relational.Specification.Tests/Update/JsonUpdateFixtureBase.cs index 12882510088..58e37c1491b 100644 --- a/test/EFCore.Relational.Specification.Tests/Update/JsonUpdateFixtureBase.cs +++ b/test/EFCore.Relational.Specification.Tests/Update/JsonUpdateFixtureBase.cs @@ -200,38 +200,6 @@ protected override void OnModelCreating(ModelBuilder modelBuilder, DbContext con b.Property(x => x.Name); }); - modelBuilder.Entity(b => - { - b.Property(x => x.Id).ValueGeneratedNever(); - b.HasMany(x => x.Attributes).WithOne().HasForeignKey(x => x.JsonEntityTphItemId); - }); - - modelBuilder.Entity(b => - { - b.HasKey(x => new { x.JsonEntityTphItemId, x.Key }); - b.HasDiscriminator("Discriminator") - .HasValue("string") - .HasValue("locale-value"); - }); - - modelBuilder.Entity(b => - { - b.Property(x => x.Value).HasColumnName("StringValue"); - }); - - modelBuilder.Entity(b => - { - b.OwnsOne(x => x.Value, bc => - { - bc.ToJson("LocaleValue"); - bc.OwnsMany(x => x.Entries, v => - { - v.Property(x => x.Locale).IsRequired(); - v.Property(x => x.Value); - }); - }); - }); - base.OnModelCreating(modelBuilder, context); } @@ -241,13 +209,11 @@ protected override Task SeedAsync(JsonQueryContext context) var jsonEntitiesInheritance = JsonQueryData.CreateJsonEntitiesInheritance(); var jsonEntitiesAllTypes = JsonQueryData.CreateJsonEntitiesAllTypes(); var jsonEntitiesConverters = JsonQueryData.CreateJsonEntitiesConverters(); - var jsonEntitiesTphItems = JsonQueryData.CreateJsonEntitiesTphItems(); context.JsonEntitiesBasic.AddRange(jsonEntitiesBasic); context.JsonEntitiesInheritance.AddRange(jsonEntitiesInheritance); context.JsonEntitiesAllTypes.AddRange(jsonEntitiesAllTypes); context.JsonEntitiesConverters.AddRange(jsonEntitiesConverters); - context.JsonEntitiesTphItems.AddRange(jsonEntitiesTphItems); return context.SaveChangesAsync(); } diff --git a/test/EFCore.Relational.Specification.Tests/Update/JsonUpdateTestBase.cs b/test/EFCore.Relational.Specification.Tests/Update/JsonUpdateTestBase.cs index 95eece37760..5a6c0cd8be3 100644 --- a/test/EFCore.Relational.Specification.Tests/Update/JsonUpdateTestBase.cs +++ b/test/EFCore.Relational.Specification.Tests/Update/JsonUpdateTestBase.cs @@ -3733,19 +3733,29 @@ public virtual Task Replace_json_reference_root_preserves_nested_owned_entities_ }); [ConditionalFact] - public virtual Task Replace_derived_entity_with_json_to_different_derived_type_with_same_key() + public virtual Task Replace_derived_entity_with_json_to_base_entity_with_same_key() => TestHelpers.ExecuteWithStrategyInTransactionAsync( CreateContext, UseTransaction, async context => { - var item = await context.JsonEntitiesTphItems.Include(x => x.Attributes).SingleAsync(); - - item.Attributes.RemoveAll(attr => attr.Key == "TextValue"); - item.Attributes.Add(new JsonEntityTphStringAttribute + var entity = await context.JsonEntitiesInheritance.OfType().SingleAsync(); + context.Remove(entity); + context.Add(new JsonEntityInheritanceBase { - Key = "TextValue", - Value = "World" + Id = entity.Id, + Name = "ReplacementBase", + ReferenceOnBase = new JsonOwnedBranch + { + Date = new DateTime(2010, 1, 1), + Fraction = 1.0m, + Enum = JsonEnum.One, + Enums = [JsonEnum.One], + NullableEnums = [null], + OwnedReferenceLeaf = new JsonOwnedLeaf { SomethingSomething = "leaf" }, + OwnedCollectionLeaf = [] + }, + CollectionOnBase = [] }); ClearLog(); @@ -3753,11 +3763,9 @@ public virtual Task Replace_derived_entity_with_json_to_different_derived_type_w }, async context => { - var item = await context.JsonEntitiesTphItems.Include(x => x.Attributes).SingleAsync(); - var attribute = Assert.Single(item.Attributes); - var stringAttribute = Assert.IsType(attribute); - Assert.Equal("TextValue", stringAttribute.Key); - Assert.Equal("World", stringAttribute.Value); + var entity = await context.JsonEntitiesInheritance.SingleAsync(x => x.Id == 2); + Assert.IsNotType(entity); + Assert.Equal("ReplacementBase", entity.Name); }); public void UseTransaction(DatabaseFacade facade, IDbContextTransaction transaction) diff --git a/test/EFCore.Specification.Tests/Query/JsonQueryFixtureBase.cs b/test/EFCore.Specification.Tests/Query/JsonQueryFixtureBase.cs index c14abe1ff82..e3dba32f797 100644 --- a/test/EFCore.Specification.Tests/Query/JsonQueryFixtureBase.cs +++ b/test/EFCore.Specification.Tests/Query/JsonQueryFixtureBase.cs @@ -644,20 +644,6 @@ protected override void OnModelCreating(ModelBuilder modelBuilder, DbContext con x => x == "Y" ? true : false, x => x == true ? "Y" : "N")); }); - - modelBuilder.Entity(b => - { - b.Property(x => x.Id).ValueGeneratedNever(); - b.HasMany(x => x.Attributes).WithOne().HasForeignKey(x => x.JsonEntityTphItemId); - }); - - modelBuilder.Entity(b => - { - b.HasKey(x => new { x.JsonEntityTphItemId, x.Key }); - b.HasDiscriminator("Discriminator") - .HasValue("string") - .HasValue("locale-value"); - }); } protected override string StoreName diff --git a/test/EFCore.Specification.Tests/TestModels/JsonQuery/JsonEntityTphItem.cs b/test/EFCore.Specification.Tests/TestModels/JsonQuery/JsonEntityTphItem.cs deleted file mode 100644 index 50d62760365..00000000000 --- a/test/EFCore.Specification.Tests/TestModels/JsonQuery/JsonEntityTphItem.cs +++ /dev/null @@ -1,13 +0,0 @@ -// 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.JsonQuery; - -#nullable disable - -public class JsonEntityTphItem -{ - public int Id { get; set; } - public string Name { get; set; } - public List Attributes { get; set; } -} diff --git a/test/EFCore.Specification.Tests/TestModels/JsonQuery/JsonEntityTphItemAttribute.cs b/test/EFCore.Specification.Tests/TestModels/JsonQuery/JsonEntityTphItemAttribute.cs deleted file mode 100644 index c35f6dee5c0..00000000000 --- a/test/EFCore.Specification.Tests/TestModels/JsonQuery/JsonEntityTphItemAttribute.cs +++ /dev/null @@ -1,12 +0,0 @@ -// 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.JsonQuery; - -#nullable disable - -public abstract class JsonEntityTphItemAttribute -{ - public int JsonEntityTphItemId { get; set; } - public string Key { get; set; } -} diff --git a/test/EFCore.Specification.Tests/TestModels/JsonQuery/JsonEntityTphLocaleAttribute.cs b/test/EFCore.Specification.Tests/TestModels/JsonQuery/JsonEntityTphLocaleAttribute.cs deleted file mode 100644 index e855780065f..00000000000 --- a/test/EFCore.Specification.Tests/TestModels/JsonQuery/JsonEntityTphLocaleAttribute.cs +++ /dev/null @@ -1,11 +0,0 @@ -// 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.JsonQuery; - -#nullable disable - -public class JsonEntityTphLocaleAttribute : JsonEntityTphItemAttribute -{ - public JsonOwnedTphLocaleValue Value { get; set; } -} diff --git a/test/EFCore.Specification.Tests/TestModels/JsonQuery/JsonEntityTphStringAttribute.cs b/test/EFCore.Specification.Tests/TestModels/JsonQuery/JsonEntityTphStringAttribute.cs deleted file mode 100644 index 866cb8b1335..00000000000 --- a/test/EFCore.Specification.Tests/TestModels/JsonQuery/JsonEntityTphStringAttribute.cs +++ /dev/null @@ -1,11 +0,0 @@ -// 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.JsonQuery; - -#nullable disable - -public class JsonEntityTphStringAttribute : JsonEntityTphItemAttribute -{ - public string Value { get; set; } -} diff --git a/test/EFCore.Specification.Tests/TestModels/JsonQuery/JsonOwnedTphLocaleValue.cs b/test/EFCore.Specification.Tests/TestModels/JsonQuery/JsonOwnedTphLocaleValue.cs deleted file mode 100644 index 76b3c3a2a86..00000000000 --- a/test/EFCore.Specification.Tests/TestModels/JsonQuery/JsonOwnedTphLocaleValue.cs +++ /dev/null @@ -1,11 +0,0 @@ -// 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.JsonQuery; - -#nullable disable - -public class JsonOwnedTphLocaleValue -{ - public List Entries { get; set; } -} diff --git a/test/EFCore.Specification.Tests/TestModels/JsonQuery/JsonOwnedTphLocaleValueEntry.cs b/test/EFCore.Specification.Tests/TestModels/JsonQuery/JsonOwnedTphLocaleValueEntry.cs deleted file mode 100644 index 8ac065a4989..00000000000 --- a/test/EFCore.Specification.Tests/TestModels/JsonQuery/JsonOwnedTphLocaleValueEntry.cs +++ /dev/null @@ -1,12 +0,0 @@ -// 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.JsonQuery; - -#nullable disable - -public class JsonOwnedTphLocaleValueEntry -{ - public string Locale { get; set; } - public string Value { get; set; } -} diff --git a/test/EFCore.Specification.Tests/TestModels/JsonQuery/JsonQueryContext.cs b/test/EFCore.Specification.Tests/TestModels/JsonQuery/JsonQueryContext.cs index ff3d2526615..b6010b6182f 100644 --- a/test/EFCore.Specification.Tests/TestModels/JsonQuery/JsonQueryContext.cs +++ b/test/EFCore.Specification.Tests/TestModels/JsonQuery/JsonQueryContext.cs @@ -16,7 +16,6 @@ public class JsonQueryContext(DbContextOptions options) : DbContext(options) public DbSet JsonEntitiesInheritance { get; set; } public DbSet JsonEntitiesAllTypes { get; set; } public DbSet JsonEntitiesConverters { get; set; } - public DbSet JsonEntitiesTphItems { get; set; } public static Task SeedAsync(JsonQueryContext context) { @@ -41,10 +40,6 @@ public static Task SeedAsync(JsonQueryContext context) context.JsonEntitiesInheritance.AddRange(jsonEntitiesInheritance); context.JsonEntitiesAllTypes.AddRange(jsonEntitiesAllTypes); context.JsonEntitiesConverters.AddRange(jsonEntitiesConverters); - - var jsonEntitiesTphItems = JsonQueryData.CreateJsonEntitiesTphItems(); - context.JsonEntitiesTphItems.AddRange(jsonEntitiesTphItems); - return context.SaveChangesAsync(); } } diff --git a/test/EFCore.Specification.Tests/TestModels/JsonQuery/JsonQueryData.cs b/test/EFCore.Specification.Tests/TestModels/JsonQuery/JsonQueryData.cs index 3e9f46e92ce..6a65549b664 100644 --- a/test/EFCore.Specification.Tests/TestModels/JsonQuery/JsonQueryData.cs +++ b/test/EFCore.Specification.Tests/TestModels/JsonQuery/JsonQueryData.cs @@ -22,7 +22,6 @@ public JsonQueryData() JsonEntitiesInheritance = CreateJsonEntitiesInheritance(); JsonEntitiesAllTypes = CreateJsonEntitiesAllTypes(); JsonEntitiesConverters = CreateJsonEntitiesConverters(); - JsonEntitiesTphItems = CreateJsonEntitiesTphItems(); } public IReadOnlyList EntitiesBasic { get; } @@ -34,7 +33,6 @@ public JsonQueryData() public IReadOnlyList JsonEntitiesInheritance { get; set; } public IReadOnlyList JsonEntitiesAllTypes { get; set; } public IReadOnlyList JsonEntitiesConverters { get; set; } - public IReadOnlyList JsonEntitiesTphItems { get; set; } public static IReadOnlyList CreateJsonEntitiesBasic() { @@ -1472,30 +1470,6 @@ public static IReadOnlyList CreateJsonEntitiesConverters() }; } - public static IReadOnlyList CreateJsonEntitiesTphItems() - => new List - { - new() - { - Id = 1, - Name = "Product 1", - Attributes = - [ - new JsonEntityTphLocaleAttribute - { - Key = "TextValue", - Value = new JsonOwnedTphLocaleValue - { - Entries = - [ - new JsonOwnedTphLocaleValueEntry { Locale = "en-US", Value = "Hello" } - ] - } - } - ] - } - }; - public IQueryable Set() where TEntity : class { @@ -1549,11 +1523,6 @@ public IQueryable Set() return (IQueryable)JsonEntitiesBasicForCollection.AsQueryable(); } - if (typeof(TEntity) == typeof(JsonEntityTphItem)) - { - return (IQueryable)JsonEntitiesTphItems.AsQueryable(); - } - throw new InvalidOperationException("Invalid entity type: " + typeof(TEntity)); } } diff --git a/test/EFCore.SqlServer.FunctionalTests/Update/JsonUpdateJsonTypeSqlServerFixture.cs b/test/EFCore.SqlServer.FunctionalTests/Update/JsonUpdateJsonTypeSqlServerFixture.cs index 26c1b3bc5bb..bdbcae78afa 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Update/JsonUpdateJsonTypeSqlServerFixture.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Update/JsonUpdateJsonTypeSqlServerFixture.cs @@ -68,10 +68,5 @@ protected override void OnModelCreating(ModelBuilder modelBuilder, DbContext con }); modelBuilder.Entity().OwnsOne(x => x.Reference).ToJson().HasColumnType("json"); - - modelBuilder.Entity(b => - { - b.OwnsOne(x => x.Value).ToJson().HasColumnType("json"); - }); } } diff --git a/test/EFCore.SqlServer.FunctionalTests/Update/JsonUpdateJsonTypeSqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Update/JsonUpdateJsonTypeSqlServerTest.cs index dd1bf78c384..de77d0a1eac 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Update/JsonUpdateJsonTypeSqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Update/JsonUpdateJsonTypeSqlServerTest.cs @@ -3299,9 +3299,9 @@ FROM [JsonEntitiesBasic] AS [j] protected override void ClearLog() => Fixture.TestSqlLoggerFactory.Clear(); - public override async Task Replace_derived_entity_with_json_to_different_derived_type_with_same_key() + public override async Task Replace_derived_entity_with_json_to_base_entity_with_same_key() { - await base.Replace_derived_entity_with_json_to_different_derived_type_with_same_key(); + await base.Replace_derived_entity_with_json_to_base_entity_with_same_key(); } private void AssertSql(params string[] expected) From 5eccfac6059a7d75b7a5ac3cb40094108356af0b Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 3 Mar 2026 00:31:23 +0000 Subject: [PATCH 7/8] Add AssertSql baseline to Replace_derived_entity_with_json_to_base_entity_with_same_key in JsonUpdateJsonTypeSqlServerTest Co-authored-by: AndriySvyryd <6539701+AndriySvyryd@users.noreply.github.com> --- .../Update/JsonUpdateJsonTypeSqlServerTest.cs | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/test/EFCore.SqlServer.FunctionalTests/Update/JsonUpdateJsonTypeSqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Update/JsonUpdateJsonTypeSqlServerTest.cs index de77d0a1eac..a8a747d71b8 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Update/JsonUpdateJsonTypeSqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Update/JsonUpdateJsonTypeSqlServerTest.cs @@ -3302,6 +3302,27 @@ protected override void ClearLog() public override async Task Replace_derived_entity_with_json_to_base_entity_with_same_key() { await base.Replace_derived_entity_with_json_to_base_entity_with_same_key(); + + AssertSql( + """ +@p0='[]' (Nullable = false) (Size = 2) +@p1='{"Date":"2010-01-01T00:00:00","Enum":-1,"Enums":[-1],"Fraction":1.0,"Id":0,"NullableEnum":null,"NullableEnums":[null],"OwnedCollectionLeaf":[],"OwnedReferenceLeaf":{"SomethingSomething":"leaf"}}' (Nullable = false) (Size = 194) +@p4='2' +@p2='JsonEntityInheritanceBase' (Nullable = false) (Size = 34) +@p3='ReplacementBase' (Size = 4000) + +SET IMPLICIT_TRANSACTIONS OFF; +SET NOCOUNT ON; +UPDATE [JsonEntitiesInheritance] SET [CollectionOnBase] = @p0, [ReferenceOnBase] = @p1, [Discriminator] = @p2, [Name] = @p3 +OUTPUT 1 +WHERE [Id] = @p4; +""", + // + """ +SELECT TOP(2) [j].[Id], [j].[Discriminator], [j].[Name], [j].[Fraction], [j].[CollectionOnBase], [j].[ReferenceOnBase], [j].[CollectionOnDerived], [j].[ReferenceOnDerived] +FROM [JsonEntitiesInheritance] AS [j] +WHERE [j].[Id] = 2 +"""); } private void AssertSql(params string[] expected) From 3b06e331ced93735ad48405bf5285851f507813e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 3 Mar 2026 00:40:42 +0000 Subject: [PATCH 8/8] Make currentEntry nullable and remove null-forgiving operator on FindPrincipal call Co-authored-by: AndriySvyryd <6539701+AndriySvyryd@users.noreply.github.com> --- src/EFCore.Relational/Update/ModificationCommand.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/EFCore.Relational/Update/ModificationCommand.cs b/src/EFCore.Relational/Update/ModificationCommand.cs index 2401d350f7a..4fa300c871a 100644 --- a/src/EFCore.Relational/Update/ModificationCommand.cs +++ b/src/EFCore.Relational/Update/ModificationCommand.cs @@ -581,17 +581,17 @@ void HandleSharedColumns( static List? FindJsonPartialUpdateInfo(IUpdateEntry entry, List processedEntries) { var result = new List(); - var currentEntry = entry; + IUpdateEntry? currentEntry = entry; var currentOwnership = currentEntry.EntityType.FindOwnership()!; - while (currentEntry.EntityType.IsMappedToJson()) + while (currentEntry is not null && currentEntry.EntityType.IsMappedToJson()) { var jsonPropertyName = currentEntry.EntityType.GetJsonPropertyName()!; currentOwnership = currentEntry.EntityType.FindOwnership()!; var previousEntry = currentEntry; #pragma warning disable EF1001 // Internal EF Core API usage. currentEntry = ((InternalEntityEntry)currentEntry).StateManager.FindPrincipal( - (InternalEntityEntry)currentEntry, currentOwnership)!; + (InternalEntityEntry)currentEntry, currentOwnership); #pragma warning restore EF1001 // Internal EF Core API usage. if (currentEntry == null || processedEntries.Contains(currentEntry)) @@ -635,7 +635,7 @@ void HandleSharedColumns( } // parent entity got deleted, no need to do any json-specific processing - if (currentEntry.EntityState == EntityState.Deleted) + if (currentEntry?.EntityState == EntityState.Deleted) { return null; }