Skip to content
10 changes: 5 additions & 5 deletions src/EFCore.Relational/Update/ModificationCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -581,20 +581,20 @@ void HandleSharedColumns(
static List<JsonPartialUpdatePathEntry>? FindJsonPartialUpdateInfo(IUpdateEntry entry, List<IUpdateEntry> processedEntries)
{
var result = new List<JsonPartialUpdatePathEntry>();
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 (processedEntries.Contains(currentEntry))
if (currentEntry == null || processedEntries.Contains(currentEntry))
{
return null;
}
Expand Down Expand Up @@ -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;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3732,6 +3732,42 @@ 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_base_entity_with_same_key()
=> TestHelpers.ExecuteWithStrategyInTransactionAsync(
CreateContext,
UseTransaction,
async context =>
{
var entity = await context.JsonEntitiesInheritance.OfType<JsonEntityInheritanceDerived>().SingleAsync();
context.Remove(entity);
context.Add(new JsonEntityInheritanceBase
{
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();
await context.SaveChangesAsync();
},
async context =>
{
var entity = await context.JsonEntitiesInheritance.SingleAsync(x => x.Id == 2);
Assert.IsNotType<JsonEntityInheritanceDerived>(entity);
Assert.Equal("ReplacementBase", entity.Name);
});

public void UseTransaction(DatabaseFacade facade, IDbContextTransaction transaction)
=> facade.UseTransaction(transaction.GetDbTransaction());

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3299,6 +3299,32 @@ FROM [JsonEntitiesBasic] AS [j]
protected override void ClearLog()
=> Fixture.TestSqlLoggerFactory.Clear();

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
""");
}
Comment thread
AndriySvyryd marked this conversation as resolved.

private void AssertSql(params string[] expected)
=> Fixture.TestSqlLoggerFactory.AssertBaseline(expected);
}
Loading