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

Query: Improve logic to find column names in TPC #28198

Merged
1 commit merged into from
Jun 9, 2022
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: 7 additions & 8 deletions src/EFCore.Relational/Query/SqlExpressions/SelectExpression.cs
Original file line number Diff line number Diff line change
Expand Up @@ -224,18 +224,17 @@ internal SelectExpression(IEntityType entityType, ISqlExpressionFactory sqlExpre
var tables = entityTypes.Select(e => GetTableBase(e)).ToArray();
var properties = GetAllPropertiesInHierarchy(entityType).ToArray();
var propertyNamesMap = new Dictionary<IProperty, string>();
foreach (var property in entityTypes[0].GetProperties())
{
propertyNamesMap[property] = tables[0].FindColumn(property)!.Name;
}
for (var i = 1; i < entityTypes.Length; i++)
for (var i = 0; i < entityTypes.Length; i++)
{
foreach (var property in entityTypes[i].GetDeclaredProperties())
foreach (var property in entityTypes[i].GetProperties())
{
Check.DebugAssert(!propertyNamesMap.ContainsKey(property), "Duplicate property found.");
propertyNamesMap[property] = tables[i].FindColumn(property)!.Name;
if (!propertyNamesMap.ContainsKey(property))
{
propertyNamesMap[property] = tables[i].FindColumn(property)!.Name;
}
}
}

var propertyNames = new string[properties.Length];
for (var i = 0; i < properties.Length; i++)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,36 @@ protected class MyEntity
public DateTime SomeDate { get; set; }
public static DateTime Modify(DateTime date) => throw new NotSupportedException();
}

[ConditionalTheory]
[MemberData(nameof(IsAsyncData))]
public virtual Task Hierarchy_query_with_abstract_type_sibling_TPC(bool async)
{
return Hierarchy_query_with_abstract_type_sibling_helper(async,
mb =>
{
mb.Entity<Animal>().UseTpcMappingStrategy();
mb.Entity<Pet>().ToTable("Pets");
mb.Entity<Cat>().ToTable("Cats");
mb.Entity<Dog>().ToTable("Dogs");
mb.Entity<FarmAnimal>().ToTable("FarmAnimals");
});
}

[ConditionalTheory]
[MemberData(nameof(IsAsyncData))]
public virtual Task Hierarchy_query_with_abstract_type_sibling_TPT(bool async)
{
return Hierarchy_query_with_abstract_type_sibling_helper(async,
mb =>
{
mb.Entity<Animal>().UseTptMappingStrategy();
mb.Entity<Pet>().ToTable("Pets");
mb.Entity<Cat>().ToTable("Cats");
mb.Entity<Dog>().ToTable("Dogs");
mb.Entity<FarmAnimal>().ToTable("FarmAnimals");
});
}
}
}

Expand Down
76 changes: 76 additions & 0 deletions test/EFCore.Specification.Tests/Query/SimpleQueryTestBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1256,4 +1256,80 @@ protected class SearchResult
public int RowId { get; set; }
public string DistinctValue { get; set; }
}

[ConditionalTheory]
[MemberData(nameof(IsAsyncData))]
public virtual Task Hierarchy_query_with_abstract_type_sibling(bool async)
{
return Hierarchy_query_with_abstract_type_sibling_helper(async, null);
}

public virtual async Task Hierarchy_query_with_abstract_type_sibling_helper(bool async, Action<ModelBuilder> onModelCreating)
{
var contextFactory = await InitializeAsync<Context28196>(onModelCreating: onModelCreating, seed: c => c.Seed());
using var context = contextFactory.CreateContext();

var query = context.Animals.OfType<Pet>().Where(a => a.Species.StartsWith("F"));

var result = async
? await query.ToListAsync()
: query.ToList();
}

protected class Context28196 : DbContext
{
public Context28196(DbContextOptions options)
: base(options)
{
}

public DbSet<Animal> Animals { get; set; }

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Animal>().Property(e => e.Id).ValueGeneratedNever();
modelBuilder.Entity<Pet>();
modelBuilder.Entity<Cat>();
modelBuilder.Entity<Dog>();
modelBuilder.Entity<FarmAnimal>();
}

public void Seed()
{
AddRange(
new Cat { Id = 1, Name = "Alice", Species = "Felis catus", EdcuationLevel = "MBA" },
new Cat { Id = 2, Name = "Mac", Species = "Felis catus", EdcuationLevel = "BA" },
new Dog { Id = 3, Name = "Toast", Species = "Canis familiaris", FavoriteToy = "Mr. Squirrel" },
new FarmAnimal { Id = 4, Value = 100.0, Species = "Ovis aries" });

SaveChanges();
}
}

protected abstract class Animal
{
public int Id { get; set; }
public string Species { get; set; }
}

protected class FarmAnimal : Animal
{
public double Value { get; set; }
}

protected abstract class Pet : Animal
{
public string Name { get; set; }
}

protected class Cat : Pet
{
public string EdcuationLevel { get; set; }
}

protected class Dog : Pet
{
public string FavoriteToy { get; set; }
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -429,4 +429,46 @@ HAVING COUNT(*) = 1
WHERE [t].[TableId] = 123
ORDER BY [t].[ParcelNumber]");
}

public override async Task Hierarchy_query_with_abstract_type_sibling(bool async)
{
await base.Hierarchy_query_with_abstract_type_sibling(async);

AssertSql(
@"SELECT [a].[Id], [a].[Discriminator], [a].[Species], [a].[Name], [a].[EdcuationLevel], [a].[FavoriteToy]
FROM [Animals] AS [a]
WHERE [a].[Discriminator] IN (N'Cat', N'Dog') AND [a].[Species] IS NOT NULL AND ([a].[Species] LIKE N'F%')");
}

public override async Task Hierarchy_query_with_abstract_type_sibling_TPT(bool async)
{
await base.Hierarchy_query_with_abstract_type_sibling_TPT(async);

AssertSql(
@"SELECT [a].[Id], [a].[Species], [p].[Name], [c].[EdcuationLevel], [d].[FavoriteToy], CASE
WHEN [d].[Id] IS NOT NULL THEN N'Dog'
WHEN [c].[Id] IS NOT NULL THEN N'Cat'
END AS [Discriminator]
FROM [Animals] AS [a]
LEFT JOIN [Pets] AS [p] ON [a].[Id] = [p].[Id]
LEFT JOIN [Cats] AS [c] ON [a].[Id] = [c].[Id]
LEFT JOIN [Dogs] AS [d] ON [a].[Id] = [d].[Id]
WHERE ([d].[Id] IS NOT NULL OR [c].[Id] IS NOT NULL) AND [a].[Species] IS NOT NULL AND ([a].[Species] LIKE N'F%')");
}

public override async Task Hierarchy_query_with_abstract_type_sibling_TPC(bool async)
{
await base.Hierarchy_query_with_abstract_type_sibling_TPC(async);

AssertSql(
@"SELECT [t].[Id], [t].[Species], [t].[Name], [t].[EdcuationLevel], [t].[FavoriteToy], [t].[Discriminator]
FROM (
SELECT [c].[Id], [c].[Species], [c].[Name], [c].[EdcuationLevel], NULL AS [FavoriteToy], N'Cat' AS [Discriminator]
FROM [Cats] AS [c]
UNION ALL
SELECT [d].[Id], [d].[Species], [d].[Name], NULL AS [EdcuationLevel], [d].[FavoriteToy], N'Dog' AS [Discriminator]
FROM [Dogs] AS [d]
) AS [t]
WHERE [t].[Species] IS NOT NULL AND ([t].[Species] LIKE N'F%')");
}
}