Skip to content

Commit

Permalink
Cosmos: Stop attempting to include navigations not defined for the co…
Browse files Browse the repository at this point in the history
…ncrete type being materialized

Fixes #26257
  • Loading branch information
ajcvickers committed Sep 6, 2022
1 parent 706a3e8 commit 55702e8
Show file tree
Hide file tree
Showing 4 changed files with 93 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -368,18 +368,23 @@ private void AddInclude(
var navigationExpression = Visit(includeExpression.NavigationExpression);

shaperExpressions.Add(
Expression.Call(
includeMethod.MakeGenericMethod(includingClrType, relatedEntityClrType),
entityEntryVariable,
instanceVariable,
concreteEntityTypeVariable,
navigationExpression,
Expression.Constant(navigation),
Expression.Constant(inverseNavigation, typeof(INavigation)),
Expression.Constant(fixup),
Expression.Constant(initialize, typeof(Action<>).MakeGenericType(includingClrType)),
Expression.IfThen(
Expression.Call(
Expression.Constant(navigation.DeclaringEntityType, typeof(IReadOnlyEntityType)),
IsAssignableFromMethodInfo,
Expression.Convert(concreteEntityTypeVariable, typeof(IReadOnlyEntityType))),
Expression.Call(
includeMethod.MakeGenericMethod(includingClrType, relatedEntityClrType),
entityEntryVariable,
instanceVariable,
concreteEntityTypeVariable,
navigationExpression,
Expression.Constant(navigation),
Expression.Constant(inverseNavigation, typeof(INavigation)),
Expression.Constant(fixup),
Expression.Constant(initialize, typeof(Action<>).MakeGenericType(includingClrType)),
#pragma warning disable EF1001 // Internal EF Core API usage.
Expression.Constant(includeExpression.SetLoaded)));
Expression.Constant(includeExpression.SetLoaded))));
#pragma warning restore EF1001 // Internal EF Core API usage.
}

Expand Down Expand Up @@ -562,6 +567,9 @@ private static readonly MethodInfo PopulateCollectionMethodInfo
= typeof(CosmosProjectionBindingRemovingExpressionVisitorBase).GetTypeInfo()
.GetDeclaredMethod(nameof(PopulateCollection));

private static readonly MethodInfo IsAssignableFromMethodInfo
= typeof(IReadOnlyEntityType).GetMethod(nameof(IReadOnlyEntityType.IsAssignableFrom), new[] { typeof(IReadOnlyEntityType) })!;

private static TCollection PopulateCollection<TEntity, TCollection>(
IClrCollectionAccessor accessor,
IEnumerable<TEntity> entities)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -829,6 +829,10 @@ protected override void OnModelCreating(ModelBuilder modelBuilder, DbContext con

modelBuilder.Entity<Fink>().HasData(
new { Id = 1, BartonId = 1 });

modelBuilder.Entity<Balloon>();
modelBuilder.Entity<HydrogenBalloon>().OwnsOne(e => e.Gas);
modelBuilder.Entity<HeliumBalloon>().OwnsOne(e => e.Gas);
}
}
}
66 changes: 66 additions & 0 deletions test/EFCore.Specification.Tests/Query/OwnedQueryTestBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,43 @@ protected OwnedQueryTestBase(TFixture fixture)
fixture.ListLoggerFactory.Clear();
}

[ConditionalTheory] // Issue #26257
[MemberData(nameof(IsAsyncData))]
public virtual async Task Can_query_owner_with_different_owned_types_having_same_property_name_in_hierarchy(bool async)
{
using (var context = CreateContext())
{
context.Add(new HeliumBalloon
{
Id = Guid.NewGuid().ToString(),
Gas = new Helium(),
});

context.Add(new HydrogenBalloon
{
Id = Guid.NewGuid().ToString(),
Gas = new Hydrogen()
});

_ = async ? await context.SaveChangesAsync() : context.SaveChanges();
}

using (var context = CreateContext())
{
var balloons = async
? await context.Set<Balloon>().ToListAsync()
: context.Set<Balloon>().ToList();

Assert.NotEmpty(balloons);
var heliumBalloons = balloons.OfType<HeliumBalloon>().ToList();
var hydrogenBalloons = balloons.OfType<HydrogenBalloon>().ToList();
Assert.Equal(heliumBalloons.Count, hydrogenBalloons.Count);

Assert.All(heliumBalloons, b => Assert.IsType<Helium>(b.Gas));
Assert.All(hydrogenBalloons, b => Assert.IsType<Hydrogen>(b.Gas));
}
}

[ConditionalTheory]
[MemberData(nameof(IsAsyncData))]
public virtual Task Query_with_owned_entity_equality_operator(bool async)
Expand Down Expand Up @@ -1465,6 +1502,10 @@ protected override void OnModelCreating(ModelBuilder modelBuilder, DbContext con

modelBuilder.Entity<Fink>().HasData(
new { Id = 1, BartonId = 1 });

modelBuilder.Entity<Balloon>();
modelBuilder.Entity<HydrogenBalloon>().OwnsOne(e => e.Gas);
modelBuilder.Entity<HeliumBalloon>().OwnsOne(e => e.Gas);
}

public override DbContextOptionsBuilder AddOptions(DbContextOptionsBuilder builder)
Expand Down Expand Up @@ -1939,4 +1980,29 @@ protected class Throned
public int Value { get; set; }
public string Property { get; set; }
}

protected abstract class Balloon
{
public string Id { get; set; }
}

protected class Helium
{
public int X { get; set; }
}

protected class Hydrogen
{
public int Y { get; set; }
}

protected class HeliumBalloon : Balloon
{
public Helium Gas { get; set; }
}

protected class HydrogenBalloon : Balloon
{
public Hydrogen Gas { get; set; }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -1686,6 +1686,10 @@ protected override void OnModelCreating(ModelBuilder modelBuilder, DbContext con
modelBuilder.Entity<Fink>()
.ToTable(tb => tb.IsTemporal())
.HasData(new { Id = 1, BartonId = 1 });

modelBuilder.Entity<Balloon>();
modelBuilder.Entity<HydrogenBalloon>().OwnsOne(e => e.Gas);
modelBuilder.Entity<HeliumBalloon>().OwnsOne(e => e.Gas);
}

protected override void Seed(PoolableDbContext context)
Expand Down

0 comments on commit 55702e8

Please sign in to comment.