Skip to content

Commit

Permalink
Fix split query over GroupBy over parameter (#30024)
Browse files Browse the repository at this point in the history
Fixes #30022
  • Loading branch information
roji committed Jan 11, 2023
1 parent 9c2e9d1 commit ef29a5a
Show file tree
Hide file tree
Showing 17 changed files with 181 additions and 30 deletions.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions src/EFCore.Relational/Properties/RelationalStrings.resx
Original file line number Diff line number Diff line change
Expand Up @@ -902,6 +902,9 @@
<data name="NoDbCommand" xml:space="preserve">
<value>Cannot create a DbCommand for a non-relational query.</value>
</data>
<data name="NonConstantOrParameterAsInExpressionValues" xml:space="preserve">
<value>Expression of type '{type}' isn't supported as the Values of an InExpression; only constants and parameters are supported.</value>
</data>
<data name="NoneRelationalTypeMappingOnARelationalTypeMappingSource" xml:space="preserve">
<value>'FindMapping' was called on a 'RelationalTypeMappingSource' with a non-relational 'TypeMappingInfo'.</value>
</data>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ when _groupByDiscovery

case SqlExpression sqlExpression
when !_groupByDiscovery
&& sqlExpression is not SqlConstantExpression or SqlParameterExpression
&& sqlExpression is not SqlConstantExpression and not SqlParameterExpression
&& _correlatedTerms.Contains(sqlExpression):
var outerColumn = _subquery.GenerateOuterColumn(_tableReferenceExpression, sqlExpression);
_mappings[sqlExpression] = outerColumn;
Expand Down
34 changes: 18 additions & 16 deletions src/EFCore.Relational/Query/SqlNullabilityProcessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -720,26 +720,28 @@ protected virtual SqlExpression VisitIn(InExpression inExpression, bool allowOpt
{
var inValues = new List<object?>();
var hasNullValue = false;
RelationalTypeMapping? typeMapping = null;
RelationalTypeMapping? typeMapping;

IEnumerable? values = null;
if (valuesExpression is SqlConstantExpression sqlConstant)
IEnumerable values;
switch (valuesExpression)
{
typeMapping = sqlConstant.TypeMapping;
values = (IEnumerable)sqlConstant.Value!;
}
else if (valuesExpression is SqlParameterExpression sqlParameter)
{
DoNotCache();
typeMapping = sqlParameter.TypeMapping;
values = (IEnumerable?)ParameterValues[sqlParameter.Name];
if (values == null)
{
throw new NullReferenceException();
}
case SqlConstantExpression sqlConstant:
typeMapping = sqlConstant.TypeMapping;
values = (IEnumerable)sqlConstant.Value!;
break;

case SqlParameterExpression sqlParameter:
DoNotCache();
typeMapping = sqlParameter.TypeMapping;
values = (IEnumerable?)ParameterValues[sqlParameter.Name] ?? throw new NullReferenceException();
break;

default:
throw new InvalidOperationException(
RelationalStrings.NonConstantOrParameterAsInExpressionValues(valuesExpression.GetType().Name));
}

foreach (var value in values!)
foreach (var value in values)
{
if (value == null && extractNullValues)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2197,6 +2197,26 @@ public virtual Task Skip_Take_on_grouping_element_inside_collection_projection(b
});
});

[ConditionalTheory]
[MemberData(nameof(IsAsyncData))]
public virtual Task Collection_projection_over_GroupBy_over_parameter(bool async)
{
var validIds = new List<string> { "L1 01", "L1 02" };

return AssertQuery(
async,
ss => ss.Set<Level1>()
.Where(l1 => validIds.Contains(l1.Name))
.GroupBy(l => l.Date)
.Select(g => new { g.Key, Ids = g.Select(e => e.Id) }),
elementSorter: e => e.Key,
elementAsserter: (e, a) =>
{
AssertEqual(e.Key, a.Key);
AssertCollection(e.Ids, a.Ids);
});
}

[ConditionalTheory]
[MemberData(nameof(IsAsyncData))]
public virtual Task SelectMany_over_conditional_null_source(bool async)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1453,7 +1453,7 @@ public virtual Task Include_with_cycle_does_not_throw_when_AsTracking_NoTracking

[ConditionalTheory]
[MemberData(nameof(IsAsyncData))]
public virtual Task Outer_idenfier_correctly_determined_when_doing_include_on_right_side_of_left_join(bool async)
public virtual Task Outer_identifier_correctly_determined_when_doing_include_on_right_side_of_left_join(bool async)
=> AssertQuery(
async,
ss => from cust in ss.Set<Customer>()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2319,6 +2319,28 @@ public override async Task Skip_Take_on_grouping_element_inside_collection_proje
""");
}

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

AssertSql(
"""
SELECT [t].[Date], [t0].[Id]
FROM (
SELECT [l].[Date]
FROM [LevelOne] AS [l]
WHERE [l].[Name] IN (N'L1 01', N'L1 02')
GROUP BY [l].[Date]
) AS [t]
LEFT JOIN (
SELECT [l0].[Id], [l0].[Date]
FROM [LevelOne] AS [l0]
WHERE [l0].[Name] IN (N'L1 01', N'L1 02')
) AS [t0] ON [t].[Date] = [t0].[Date]
ORDER BY [t].[Date]
""");
}

public override async Task Include_partially_added_before_Where_and_then_build_upon(bool async)
{
await base.Include_partially_added_before_Where_and_then_build_upon(async);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3003,6 +3003,28 @@ public override async Task Skip_Take_on_grouping_element_inside_collection_proje
""");
}

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

AssertSql(
"""
SELECT [t].[Date], [t0].[Id]
FROM (
SELECT [l].[Date]
FROM [Level1] AS [l]
WHERE [l].[Name] IN (N'L1 01', N'L1 02')
GROUP BY [l].[Date]
) AS [t]
LEFT JOIN (
SELECT [l0].[Id], [l0].[Date]
FROM [Level1] AS [l0]
WHERE [l0].[Name] IN (N'L1 01', N'L1 02')
) AS [t0] ON [t].[Date] = [t0].[Date]
ORDER BY [t].[Date]
""");
}

public override async Task Filtered_include_is_considered_loaded(bool async)
{
await base.Filtered_include_is_considered_loaded(async);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3728,6 +3728,36 @@ public override async Task Skip_Take_on_grouping_element_inside_collection_proje
""");
}

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

AssertSql(
"""
SELECT [l].[Date]
FROM [LevelOne] AS [l]
WHERE [l].[Name] IN (N'L1 01', N'L1 02')
GROUP BY [l].[Date]
ORDER BY [l].[Date]
""",
//
"""
SELECT [t0].[Id], [t].[Date]
FROM (
SELECT [l].[Date]
FROM [LevelOne] AS [l]
WHERE [l].[Name] IN (N'L1 01', N'L1 02')
GROUP BY [l].[Date]
) AS [t]
INNER JOIN (
SELECT [l0].[Id], [l0].[Date]
FROM [LevelOne] AS [l0]
WHERE [l0].[Name] IN (N'L1 01', N'L1 02')
) AS [t0] ON [t].[Date] = [t0].[Date]
ORDER BY [t].[Date]
""");
}

public override async Task Include_partially_added_before_Where_and_then_build_upon(bool async)
{
await base.Include_partially_added_before_Where_and_then_build_upon(async);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1262,9 +1262,9 @@ public override async Task Include_multiple_references_then_include_collection_m
""");
}

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

AssertSql(
"""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -261,9 +261,9 @@ public override async Task Include_collection_then_include_collection_predicate(
""");
}

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

AssertSql(
"""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1712,9 +1712,9 @@ public override async Task Filtered_include_with_multiple_ordering(bool async)
""");
}

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

AssertSql(
"""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1309,9 +1309,9 @@ public override async Task Include_duplicate_reference3(bool async)
""");
}

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

AssertSql(
"""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2388,9 +2388,9 @@ public override async Task Filtered_include_with_multiple_ordering(bool async)
""");
}

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

AssertSql(
"""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1262,9 +1262,9 @@ public override async Task Include_multiple_references_then_include_collection_m
""");
}

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

AssertSql(
"""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2295,6 +2295,28 @@ public override async Task Skip_Take_on_grouping_element_inside_collection_proje
""");
}

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

AssertSql(
"""
SELECT [t].[Date], [t0].[Id]
FROM (
SELECT [l].[Date]
FROM [LevelOne] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l]
WHERE [l].[Name] IN (N'L1 01', N'L1 02')
GROUP BY [l].[Date]
) AS [t]
LEFT JOIN (
SELECT [l0].[Id], [l0].[Date]
FROM [LevelOne] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l0]
WHERE [l0].[Name] IN (N'L1 01', N'L1 02')
) AS [t0] ON [t].[Date] = [t0].[Date]
ORDER BY [t].[Date]
""");
}

public override async Task Multiple_SelectMany_navigation_property_followed_by_select_collection_navigation(bool async)
{
await base.Multiple_SelectMany_navigation_property_followed_by_select_collection_navigation(async);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3023,6 +3023,28 @@ public override async Task Skip_Take_on_grouping_element_inside_collection_proje
""");
}

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

AssertSql(
"""
SELECT [t].[Date], [t0].[Id]
FROM (
SELECT [l].[Date]
FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l]
WHERE [l].[Name] IN (N'L1 01', N'L1 02')
GROUP BY [l].[Date]
) AS [t]
LEFT JOIN (
SELECT [l0].[Id], [l0].[Date]
FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l0]
WHERE [l0].[Name] IN (N'L1 01', N'L1 02')
) AS [t0] ON [t].[Date] = [t0].[Date]
ORDER BY [t].[Date]
""");
}

public override async Task Skip_Take_on_grouping_element_into_non_entity(bool async)
{
await base.Skip_Take_on_grouping_element_into_non_entity(async);
Expand Down

0 comments on commit ef29a5a

Please sign in to comment.