Skip to content

Commit

Permalink
[release/7.0] Fix to #30273 - EF7 generating incorrect SQL for the Co…
Browse files Browse the repository at this point in the history
…ncat/Union All, The same code was working fine for EF6.4.4 (#30451)

Fixed #30273
  • Loading branch information
maumar committed Mar 14, 2023
1 parent 85d686a commit edeb38f
Show file tree
Hide file tree
Showing 3 changed files with 156 additions and 0 deletions.
12 changes: 12 additions & 0 deletions src/EFCore.Relational/Query/SqlExpressions/SelectExpression.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ public sealed partial class SelectExpression : TableExpressionBase
{
private const string DiscriminatorColumnAlias = "Discriminator";
private const string SqlQuerySingleColumnAlias = "Value";

private static readonly bool UseOldBehavior30273
= AppContext.TryGetSwitch("Microsoft.EntityFrameworkCore.Issue30273", out var enabled30273) && enabled30273;

private static readonly IdentifierComparer IdentifierComparerInstance = new();

private static readonly Dictionary<ExpressionType, ExpressionType> MirroredOperationMap =
Expand Down Expand Up @@ -3961,6 +3965,14 @@ private SelectExpression Prune(IReadOnlyCollection<string>? referencedColumns)
}
else if (table is SetOperationBase { IsDistinct: false } setOperation)
{
if (!UseOldBehavior30273)
{
if (setOperation.Source1.IsDistinct
|| setOperation.Source2.IsDistinct)
{
continue;
}
}
#if DEBUG
setOperation.Source1.Prune(columnsMap[tableAlias], removedAliases);
setOperation.Source2.Prune(columnsMap[tableAlias], removedAliases);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -877,4 +877,51 @@ public virtual Task Union_on_entity_plus_other_column_with_correlated_collection
AssertCollection(e.Orders, a.Orders);
},
entryCount: 11);

[ConditionalTheory]
[MemberData(nameof(IsAsyncData))]
public virtual Task Concat_with_pruning(bool async)
=> AssertQuery(
async,
ss => ss.Set<Customer>().Where(c => c.CustomerID.StartsWith("A"))
.Concat(ss.Set<Customer>().Where(c => c.CustomerID.StartsWith("B")))
.Select(x => x.City));

[ConditionalTheory]
[MemberData(nameof(IsAsyncData))]
public virtual Task Concat_with_distinct_on_one_source_and_pruning(bool async)
=> AssertQuery(
async,
ss => ss.Set<Customer>().Where(c => c.CustomerID.StartsWith("A"))
.Concat(ss.Set<Customer>().Where(c => c.CustomerID.StartsWith("B")).Distinct())
.Select(x => x.City));

[ConditionalTheory]
[MemberData(nameof(IsAsyncData))]
public virtual Task Concat_with_distinct_on_both_source_and_pruning(bool async)
=> AssertQuery(
async,
ss => ss.Set<Customer>().Where(c => c.CustomerID.StartsWith("A")).Distinct()
.Concat(ss.Set<Customer>().Where(c => c.CustomerID.StartsWith("B")).Distinct())
.Select(x => x.City));

[ConditionalTheory]
[MemberData(nameof(IsAsyncData))]
public virtual Task Nested_concat_with_pruning(bool async)
=> AssertQuery(
async,
ss => ss.Set<Customer>().Where(c => c.CustomerID.StartsWith("A"))
.Concat(ss.Set<Customer>().Where(c => c.CustomerID.StartsWith("B")))
.Concat(ss.Set<Customer>().Where(c => c.CustomerID.StartsWith("A")))
.Select(x => x.City));

[ConditionalTheory]
[MemberData(nameof(IsAsyncData))]
public virtual Task Nested_concat_with_distinct_in_the_middle_and_pruning(bool async)
=> AssertQuery(
async,
ss => ss.Set<Customer>().Where(c => c.CustomerID.StartsWith("A"))
.Concat(ss.Set<Customer>().Where(c => c.CustomerID.StartsWith("B")).Distinct())
.Concat(ss.Set<Customer>().Where(c => c.CustomerID.StartsWith("A")))
.Select(x => x.City));
}
Original file line number Diff line number Diff line change
Expand Up @@ -1317,6 +1317,103 @@ public override async Task Include_Union_different_includes_throws(bool async)
AssertSql();
}

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

AssertSql(
"""
SELECT [c].[City]
FROM [Customers] AS [c]
WHERE [c].[CustomerID] LIKE N'A%'
UNION ALL
SELECT [c0].[City]
FROM [Customers] AS [c0]
WHERE [c0].[CustomerID] LIKE N'B%'
""");
}

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

AssertSql(
"""
SELECT [t].[City]
FROM (
SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region]
FROM [Customers] AS [c]
WHERE [c].[CustomerID] LIKE N'A%'
UNION ALL
SELECT DISTINCT [c0].[CustomerID], [c0].[Address], [c0].[City], [c0].[CompanyName], [c0].[ContactName], [c0].[ContactTitle], [c0].[Country], [c0].[Fax], [c0].[Phone], [c0].[PostalCode], [c0].[Region]
FROM [Customers] AS [c0]
WHERE [c0].[CustomerID] LIKE N'B%'
) AS [t]
""");
}

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

AssertSql(
"""
SELECT [t].[City]
FROM (
SELECT DISTINCT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region]
FROM [Customers] AS [c]
WHERE [c].[CustomerID] LIKE N'A%'
UNION ALL
SELECT DISTINCT [c0].[CustomerID], [c0].[Address], [c0].[City], [c0].[CompanyName], [c0].[ContactName], [c0].[ContactTitle], [c0].[Country], [c0].[Fax], [c0].[Phone], [c0].[PostalCode], [c0].[Region]
FROM [Customers] AS [c0]
WHERE [c0].[CustomerID] LIKE N'B%'
) AS [t]
""");
}

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

AssertSql(
"""
SELECT [c].[City]
FROM [Customers] AS [c]
WHERE [c].[CustomerID] LIKE N'A%'
UNION ALL
SELECT [c0].[City]
FROM [Customers] AS [c0]
WHERE [c0].[CustomerID] LIKE N'B%'
UNION ALL
SELECT [c1].[City]
FROM [Customers] AS [c1]
WHERE [c1].[CustomerID] LIKE N'A%'
""");
}

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

AssertSql(
"""
SELECT [t].[City]
FROM (
SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region]
FROM [Customers] AS [c]
WHERE [c].[CustomerID] LIKE N'A%'
UNION ALL
SELECT DISTINCT [c0].[CustomerID], [c0].[Address], [c0].[City], [c0].[CompanyName], [c0].[ContactName], [c0].[ContactTitle], [c0].[Country], [c0].[Fax], [c0].[Phone], [c0].[PostalCode], [c0].[Region]
FROM [Customers] AS [c0]
WHERE [c0].[CustomerID] LIKE N'B%'
) AS [t]
UNION ALL
SELECT [c1].[City]
FROM [Customers] AS [c1]
WHERE [c1].[CustomerID] LIKE N'A%'
""");
}

public override async Task Client_eval_Union_FirstOrDefault(bool async)
{
// Client evaluation in projection. Issue #16243.
Expand Down

0 comments on commit edeb38f

Please sign in to comment.