Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Return flattened properties of complex types in correct order #33393

Merged
merged 1 commit into from
Mar 26, 2024
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
14 changes: 7 additions & 7 deletions src/EFCore/Metadata/Internal/TypeBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1315,18 +1315,18 @@ protected static IEnumerable<T> ToEnumerable<T>(T? element)
/// <returns>The properties.</returns>
public virtual IEnumerable<Property> GetFlattenedProperties()
{
foreach (var property in GetProperties())
{
yield return property;
}

foreach (var complexProperty in GetComplexProperties())
if (_baseType != null)
{
foreach (var property in complexProperty.ComplexType.GetFlattenedProperties())
foreach (var property in _baseType.GetFlattenedProperties())
{
yield return property;
}
}

foreach (var property in GetFlattenedDeclaredProperties())
{
yield return property;
}
}

/// <summary>
Expand Down
14 changes: 7 additions & 7 deletions src/EFCore/Metadata/RuntimeTypeBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -515,18 +515,18 @@ public virtual IEnumerable<RuntimeProperty> GetFlattenedProperties()

static IEnumerable<RuntimeProperty> Create(RuntimeTypeBase type)
{
foreach (var property in type.GetProperties())
if (type._baseType != null)
{
yield return property;
}

foreach (var complexProperty in type.GetComplexProperties())
{
foreach (var property in complexProperty.ComplexType.GetFlattenedProperties())
foreach (var property in type._baseType.GetFlattenedProperties())
{
yield return property;
}
}

foreach (var property in type.GetFlattenedDeclaredProperties())
{
yield return property;
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ public override Task Complex_store_values_can_be_accessed_asynchronously_as_a_pr
=> Assert.ThrowsAsync<NullReferenceException>( // In-memory database cannot query complex types
() => base.Complex_store_values_can_be_accessed_asynchronously_as_a_property_dictionary_using_IProperty());

public override Task Values_can_be_reloaded_from_database_for_entity_in_any_state_with_inheritance(EntityState state, bool async)
=> Assert.ThrowsAnyAsync<Exception>( // In-memory database cannot query complex types
() => base.Values_can_be_reloaded_from_database_for_entity_in_any_state_with_inheritance(state, async));

public class PropertyValuesInMemoryFixture : PropertyValuesFixtureBase
{
public override DbContextOptionsBuilder AddOptions(DbContextOptionsBuilder builder)
Expand Down
112 changes: 106 additions & 6 deletions test/EFCore.Specification.Tests/PropertyValuesTestBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1282,6 +1282,53 @@ public async Task Reload_when_entity_deleted_in_store_can_happen_for_any_state(E
Assert.Contains(office, building.Offices);
}

[ConditionalTheory]
[InlineData(EntityState.Unchanged, true)]
[InlineData(EntityState.Unchanged, false)]
[InlineData(EntityState.Modified, true)]
[InlineData(EntityState.Modified, false)]
[InlineData(EntityState.Added, true)]
[InlineData(EntityState.Added, false)]
[InlineData(EntityState.Deleted, true)]
[InlineData(EntityState.Deleted, false)]
[InlineData(EntityState.Detached, true)]
[InlineData(EntityState.Detached, false)]
public virtual async Task Values_can_be_reloaded_from_database_for_entity_in_any_state_with_inheritance(EntityState state, bool async)
{
using var context = CreateContext();
var supplier = context.Set<Supplier33307>().Single();
var customer = context.Set<Customer33307>().Single();

supplier.Name = "X";
supplier.Foo = "Z";
customer.Name = "Y";
customer.Bar = 77;
customer.Address.Street = "New Road";
supplier.Address.Street = "New Lane";

context.Entry(supplier).State = state;
context.Entry(customer).State = state;

if (async)
{
await context.Entry(supplier).ReloadAsync();
await context.Entry(customer).ReloadAsync();
}
else
{
context.Entry(supplier).Reload();
context.Entry(customer).Reload();
}

Assert.Equal("Bar", customer.Name);
Assert.Equal(11, customer.Bar);
Assert.Equal("Two", customer.Address.Street);

Assert.Equal("Foo", supplier.Name);
Assert.Equal("F", supplier.Foo);
Assert.Equal("One", supplier.Address.Street);
}

[ConditionalFact]
public virtual void Current_values_can_be_set_from_an_object_using_generic_dictionary()
=> TestGenericObjectSetValues(e => e.CurrentValues, (e, n) => e.Property(n).CurrentValue!);
Expand Down Expand Up @@ -2301,6 +2348,31 @@ public string NoSetter
public required Milk Milk { get; set; }
}

[ComplexType]
public class Address33307
{
public required string Street { get; set; }
public double? Altitude { get; set; }
public int? Number { get; set; }
}

public abstract class Contact33307
{
public int Id { get; set; }
public required string Name { get; set; }
public required Address33307 Address { get; set; }
}

public class Supplier33307 : Contact33307
{
public string? Foo { get; set; }
}

public class Customer33307 : Contact33307
{
public int Bar { get; set; }
}

protected struct Culture
{
public string Species { get; set; }
Expand Down Expand Up @@ -2555,6 +2627,10 @@ protected override void OnModelCreating(ModelBuilder modelBuilder, DbContext con
});
});
});

modelBuilder.Entity<Contact33307>();
modelBuilder.Entity<Supplier33307>();
modelBuilder.Entity<Customer33307>();
}

protected override Task SeedAsync(PoolableDbContext context)
Expand Down Expand Up @@ -2678,6 +2754,30 @@ protected override Task SeedAsync(PoolableDbContext context)
Assert.True((bool)joinEntry.Entity["InitializedCalled"]);
}

context.Add(new Supplier33307
{
Name = "Foo",
Address = new()
{
Street = "One",
Altitude = Math.PI,
Number = 42,
},
Foo = "F"
});

context.Add(new Customer33307
{
Name = "Bar",
Address = new()
{
Street = "Two",
Altitude = Math.E,
Number = 42,
},
Bar = 11
});

return context.SaveChangesAsync();
}
}
Expand All @@ -2695,9 +2795,9 @@ public object CreatedInstance(MaterializationInterceptionData materializationDat
{
joinEntity["CreatedCalled"] = true;
}
else
else if (entity is PropertyValuesBase propertyValuesBase)
{
((PropertyValuesBase)entity).CreatedCalled = true;
propertyValuesBase.CreatedCalled = true;
}

return entity;
Expand All @@ -2712,9 +2812,9 @@ public InterceptionResult InitializingInstance(
{
joinEntity["InitializingCalled"] = true;
}
else
else if (entity is PropertyValuesBase propertyValuesBase)
{
((PropertyValuesBase)entity).InitializingCalled = true;
propertyValuesBase.InitializingCalled = true;
}

return result;
Expand All @@ -2726,9 +2826,9 @@ public object InitializedInstance(MaterializationInterceptionData materializatio
{
joinEntity["InitializedCalled"] = true;
}
else
else if (entity is PropertyValuesBase propertyValuesBase)
{
((PropertyValuesBase)entity).InitializedCalled = true;
propertyValuesBase.InitializedCalled = true;
}

return entity;
Expand Down
Loading