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
11 changes: 11 additions & 0 deletions src/EFCore/ChangeTracking/Internal/SnapshotFactoryFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ namespace Microsoft.EntityFrameworkCore.ChangeTracking.Internal;
/// </summary>
public abstract class SnapshotFactoryFactory
{
private static readonly bool UseOldBehavior37337 =
AppContext.TryGetSwitch("Microsoft.EntityFrameworkCore.Issue37337", out var enabled) && enabled;

/// <summary>
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
Expand Down Expand Up @@ -139,6 +142,14 @@ protected virtual Expression CreateSnapshotExpression(
continue;

case IProperty property:
// Shadow property materialization on complex types is not currently supported (see #35613).
if (!UseOldBehavior37337 && propertyBase.DeclaringType is IComplexType && property.IsShadowProperty())
{
arguments[i] = propertyBase.ClrType.GetDefaultValueConstant();
types[i] = propertyBase.ClrType;
continue;
}

arguments[i] = CreateSnapshotValueExpression(CreateReadValueExpression(parameter, property), property);
continue;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,65 @@ public class ComplexTypeWithAllNulls

#endregion 37162

#region Issue37337

[ConditionalFact]
public virtual async Task Nullable_complex_type_with_discriminator_and_shadow_property()
{
var contextFactory = await InitializeAsync<Context37337>(
seed: context =>
{
context.Add(
new Context37337.EntityType
{
Prop = new Context37337.OptionalComplexProperty
{
OptionalValue = true
}
});
return context.SaveChangesAsync();
});

await using var context = contextFactory.CreateContext();

var entities = await context.Set<Context37337.EntityType>().ToArrayAsync();

Assert.Single(entities);
var entity = entities[0];
Assert.NotNull(entity.Prop);
Assert.True(entity.Prop.OptionalValue);
}

private class Context37337(DbContextOptions options) : DbContext(options)
{
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
var entity = modelBuilder.Entity<EntityType>();
entity.Property(p => p.Id);
entity.HasKey(p => p.Id);

var compl = entity.ComplexProperty(p => p.Prop);
compl.Property(p => p.OptionalValue);
compl.HasDiscriminator();

// Shadow property added via convention (e.g., audit field)
entity.Property<string>("CreatedBy").IsRequired(false);
}

public class EntityType
{
public Guid Id { get; set; }
public OptionalComplexProperty? Prop { get; set; }
}

public class OptionalComplexProperty
{
public bool? OptionalValue { get; set; }
}
}

#endregion Issue37337

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