Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 14 additions & 1 deletion src/EFCore/ChangeTracking/Internal/InternalEntryBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -274,9 +274,22 @@ protected virtual void SetEntityState(EntityState oldState, EntityState newState
// Hot path; do not use LINQ
foreach (var property in structuralType.GetFlattenedProperties())
{
if (property.GetAfterSaveBehavior() != PropertySaveBehavior.Save)
var afterSaveBehavior = property.GetAfterSaveBehavior();
if (afterSaveBehavior != PropertySaveBehavior.Save)
{
_stateData.FlagProperty(property.GetIndex(), PropertyFlag.Modified, isFlagged: false);

// Properties with AfterSaveBehavior.Throw were unflagged above, but DetectChanges could
// re-mark them if the original values snapshot doesn't match the current values (e.g. for
// shadow properties on complex types whose snapshot stores default values).
// Set the original values of Throw properties to match current values so that
// DetectChanges won't find a false mismatch and re-mark them as modified.
if (afterSaveBehavior == PropertySaveBehavior.Throw
&& property.GetOriginalValueIndex() >= 0
&& !IsConceptualNull(property))
{
SetOriginalValue(property, this[property], skipChangeDetection: true);
}
}

// Properties that are not loaded (IsAutoLoaded = false and not yet loaded) should
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,24 @@ FROM root c
""");
}

public override async Task Update_entity_with_nullable_complex_type_and_discriminator_does_not_throw()
{
await base.Update_entity_with_nullable_complex_type_and_discriminator_does_not_throw();

Comment thread
AndriySvyryd marked this conversation as resolved.
AssertSql(
"""
SELECT VALUE c
FROM root c
OFFSET 0 LIMIT 2
""",
//
"""
SELECT VALUE c
FROM root c
OFFSET 0 LIMIT 2
""");
}

protected override DbContextOptionsBuilder AddNonSharedOptions(DbContextOptionsBuilder builder)
=> base.AddNonSharedOptions(builder)
.ConfigureWarnings(w => w.Ignore(CosmosEventId.NoPartitionKeyDefined));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -379,6 +379,59 @@ public class OptionalComplexProperty

#endregion Issue37337

#region Issue38105

[ConditionalFact]
public virtual async Task Update_entity_with_nullable_complex_type_and_discriminator_does_not_throw()
Comment thread
AndriySvyryd marked this conversation as resolved.
{
var contextFactory = await InitializeNonSharedTest<Context37337>(
seed: context =>
{
var entity = new Context37337.EntityType
{
Id = Guid.NewGuid(),
Prop = new Context37337.OptionalComplexProperty
{
OptionalValue = true
}
};
context.Add(entity);
context.Entry(entity).Property(Issue37337CreatedByShadowPropertyName).CurrentValue = "Seeder";
return context.SaveChangesAsync();
});

await using var context = contextFactory.CreateDbContext();

var entity = await context.Set<Context37337.EntityType>().SingleAsync();
var id = entity.Id;
context.ChangeTracker.Clear();

// Create a new disconnected instance with the same key and Update it.
// The complex type discriminator (shadow property with AfterSaveBehavior.Throw) should not
// be marked as modified by Update(), and SaveChanges should succeed without throwing.
var updatedEntity = new Context37337.EntityType
{
Id = id,
Prop = new Context37337.OptionalComplexProperty
{
OptionalValue = false
}
};

context.Update(updatedEntity);

await context.SaveChangesAsync();

context.ChangeTracker.Clear();

var reloaded = await context.Set<Context37337.EntityType>().SingleAsync();
Assert.Equal(id, reloaded.Id);
Assert.NotNull(reloaded.Prop);
Assert.False(reloaded.Prop.OptionalValue);
}

#endregion Issue38105

protected override string NonSharedStoreName
=> "AdHocComplexTypeQueryTest";
}
Loading