Skip to content
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -1871,7 +1871,7 @@ private sealed class GroupingAggregateScanner(ParameterExpression groupingParame
[nameof(Enumerable.Sum), nameof(Enumerable.Min), nameof(Enumerable.Max), nameof(Enumerable.Average)];

private static readonly string[] PredicateAggregateMethodNames =
[nameof(Enumerable.Count), nameof(Enumerable.LongCount)];
[nameof(Enumerable.Any), nameof(Enumerable.All), nameof(Enumerable.Count), nameof(Enumerable.LongCount)];

public List<GroupingAggregateCall> Aggregates { get; } = [];
public bool HasUnsupportedUsage { get; private set; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -386,6 +386,117 @@ public virtual Task GroupBy_Count_with_predicate_through_navigation_property(boo
.Select(g => new { g.Key, Londons = g.Count(o => o.Customer!.City == "London") }),
elementSorter: e => e.Key);

[Theory, MemberData(nameof(IsAsyncData))]
public virtual Task GroupBy_Any_with_predicate_through_navigation_property(bool async)
=> AssertQuery(
async,
ss => ss.Set<Order>()
.GroupBy(o => o.EmployeeID)
.Select(g => new { g.Key, Londons = g.Any(o => o.Customer!.City == "London") }),
elementSorter: e => e.Key);

[Theory, MemberData(nameof(IsAsyncData))]
public virtual Task GroupBy_All_with_predicate_through_navigation_property(bool async)
=> AssertQuery(
async,
ss => ss.Set<Order>()
.GroupBy(o => o.EmployeeID)
.Select(g => new { g.Key, Londons = g.All(o => o.Customer!.City == "London") }),
elementSorter: e => e.Key);

[Theory, MemberData(nameof(IsAsyncData))]
public virtual Task GroupBy_Queryable_Any_with_predicate_through_navigation_property(bool async)
=> AssertQuery(
async,
ss => ss.Set<Order>()
.GroupBy(o => o.EmployeeID)
.Select(g => new { g.Key, Londons = g.AsQueryable().Any(o => o.Customer!.City == "London") }),
elementSorter: e => e.Key);

[Theory, MemberData(nameof(IsAsyncData))]
public virtual Task GroupBy_Queryable_All_with_predicate_through_navigation_property(bool async)
=> AssertQuery(
async,
ss => ss.Set<Order>()
.GroupBy(o => o.EmployeeID)
.Select(g => new { g.Key, Londons = g.AsQueryable().All(o => o.Customer!.City == "London") }),
elementSorter: e => e.Key);

[Theory, MemberData(nameof(IsAsyncData))]
public virtual Task GroupBy_Any_and_aggregate_through_navigation_property(bool async)
=> AssertQuery(
async,
ss => ss.Set<Order>()
.GroupBy(o => o.EmployeeID)
.Select(
g => new
{
g.Key,
HasOrders = g.Any(),
Londons = g.Count(o => o.Customer!.City == "London")
}),
elementSorter: e => e.Key);

[Theory, MemberData(nameof(IsAsyncData))]
public virtual Task GroupBy_All_and_aggregate_through_navigation_property(bool async)
=> AssertQuery(
async,
ss => ss.Set<Order>()
.GroupBy(o => o.EmployeeID)
.Select(
g => new
{
g.Key,
AllLate = g.All(o => o.OrderID > 10250),
Londons = g.Count(o => o.Customer!.City == "London")
}),
elementSorter: e => e.Key);

[Theory, MemberData(nameof(IsAsyncData))]
public virtual Task GroupBy_multiple_aggregates_with_Any_and_All_sharing_same_navigation(bool async)
=> AssertQuery(
async,
ss => ss.Set<Order>()
.GroupBy(o => o.EmployeeID)
.Select(
g => new
{
g.Key,
Region = g.Max(o => o.Customer!.Region),
AnyLondon = g.Any(o => o.Customer!.City == "London"),
AllLondon = g.All(o => o.Customer!.City == "London"),
Count = g.Count()
}),
elementSorter: e => e.Key);

[Theory, MemberData(nameof(IsAsyncData))]
public virtual Task GroupBy_Any_through_two_level_navigation(bool async)
=> AssertQuery(
async,
ss => ss.Set<OrderDetail>()
.GroupBy(od => od.ProductID)
.Select(g => new { g.Key, Londons = g.Any(od => od.Order!.Customer!.City == "London") }),
elementSorter: e => e.Key);

[Theory, MemberData(nameof(IsAsyncData))]
public virtual Task GroupBy_key_and_Any_through_same_navigation(bool async)
=> AssertQuery(
async,
ss => ss.Set<Order>()
.GroupBy(o => o.Customer!.City)
.Select(g => new { g.Key, Londons = g.Any(o => o.Customer!.City == "London") }),
elementSorter: e => e.Key);

[Theory, MemberData(nameof(IsAsyncData))]
public virtual Task GroupBy_Any_through_navigation_in_intermediate_projection(bool async)
=> AssertQuery(
async,
ss => ss.Set<Order>()
.Select(o => new { o.EmployeeID, o.Customer!.City })
.GroupBy(x => x.EmployeeID)
.Select(g => new { g.Key, Londons = g.Any(x => x.City == "London") }),
elementSorter: e => e.Key);

[Theory, MemberData(nameof(IsAsyncData))]
public virtual Task GroupBy_key_and_aggregate_through_same_navigation(bool async)
=> AssertQuery(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,40 @@ public virtual Task GroupBy_aggregate_through_filtered_navigation_ignore_query_f
.Select(g => new { g.Key, Londons = g.Count(o => o.Customer!.City == "London") }),
elementSorter: e => e.Key.GetValueOrDefault());

[Theory, MemberData(nameof(IsAsyncData))]
public virtual Task GroupBy_Any_through_filtered_navigation(bool async)
=> AssertFilteredQuery(
async,
ss => ss.Set<Order>()
.GroupBy(o => o.EmployeeID)
.Select(g => new { g.Key, Londons = g.Any(o => o.Customer!.City == "London") }),
elementSorter: e => e.Key.GetValueOrDefault());

[Theory, MemberData(nameof(IsAsyncData))]
public virtual Task GroupBy_Any_through_filtered_navigation_with_total(bool async)
=> AssertFilteredQuery(
async,
ss => ss.Set<Order>()
.GroupBy(o => o.EmployeeID)
.Select(
g => new
{
g.Key,
Total = g.Count(),
Londons = g.Any(o => o.Customer!.City == "London")
}),
elementSorter: e => e.Key.GetValueOrDefault());

[Theory, MemberData(nameof(IsAsyncData))]
public virtual Task GroupBy_Any_through_filtered_navigation_ignore_query_filters(bool async)
=> AssertQuery(
async,
ss => ss.Set<Order>()
.IgnoreQueryFilters()
.GroupBy(o => o.EmployeeID)
.Select(g => new { g.Key, Londons = g.Any(o => o.Customer!.City == "London") }),
elementSorter: e => e.Key.GetValueOrDefault());

[Theory, MemberData(nameof(IsAsyncData))]
public virtual Task Included_many_to_one_query2(bool async)
=> AssertFilteredQuery(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2422,6 +2422,210 @@ GROUP BY [o].[EmployeeID]
""");
}

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

AssertSql(
"""
SELECT [o].[EmployeeID] AS [Key], CASE
WHEN EXISTS (
SELECT 1
FROM [Orders] AS [o0]
LEFT JOIN [Customers] AS [c] ON [o0].[CustomerID] = [c].[CustomerID]
WHERE ([o].[EmployeeID] = [o0].[EmployeeID] OR ([o].[EmployeeID] IS NULL AND [o0].[EmployeeID] IS NULL)) AND [c].[City] = N'London') THEN CAST(1 AS bit)
ELSE CAST(0 AS bit)
END AS [Londons]
FROM [Orders] AS [o]
GROUP BY [o].[EmployeeID]
""");
}

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

AssertSql(
"""
SELECT [o].[EmployeeID] AS [Key], CASE
WHEN NOT EXISTS (
SELECT 1
FROM [Orders] AS [o0]
LEFT JOIN [Customers] AS [c] ON [o0].[CustomerID] = [c].[CustomerID]
WHERE ([o].[EmployeeID] = [o0].[EmployeeID] OR ([o].[EmployeeID] IS NULL AND [o0].[EmployeeID] IS NULL)) AND ([c].[City] <> N'London' OR [c].[City] IS NULL)) THEN CAST(1 AS bit)
ELSE CAST(0 AS bit)
END AS [Londons]
FROM [Orders] AS [o]
GROUP BY [o].[EmployeeID]
""");
}

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

AssertSql(
"""
SELECT [o].[EmployeeID] AS [Key], CASE
WHEN EXISTS (
SELECT 1
FROM [Orders] AS [o0]
LEFT JOIN [Customers] AS [c] ON [o0].[CustomerID] = [c].[CustomerID]
WHERE ([o].[EmployeeID] = [o0].[EmployeeID] OR ([o].[EmployeeID] IS NULL AND [o0].[EmployeeID] IS NULL)) AND [c].[City] = N'London') THEN CAST(1 AS bit)
ELSE CAST(0 AS bit)
END AS [Londons]
FROM [Orders] AS [o]
GROUP BY [o].[EmployeeID]
""");
}

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

AssertSql(
"""
SELECT [o].[EmployeeID] AS [Key], CASE
WHEN NOT EXISTS (
SELECT 1
FROM [Orders] AS [o0]
LEFT JOIN [Customers] AS [c] ON [o0].[CustomerID] = [c].[CustomerID]
WHERE ([o].[EmployeeID] = [o0].[EmployeeID] OR ([o].[EmployeeID] IS NULL AND [o0].[EmployeeID] IS NULL)) AND ([c].[City] <> N'London' OR [c].[City] IS NULL)) THEN CAST(1 AS bit)
ELSE CAST(0 AS bit)
END AS [Londons]
FROM [Orders] AS [o]
GROUP BY [o].[EmployeeID]
""");
}

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

AssertSql(
"""
SELECT [o].[EmployeeID] AS [Key], CASE
WHEN EXISTS (
SELECT 1
FROM [Orders] AS [o0]
WHERE [o].[EmployeeID] = [o0].[EmployeeID] OR ([o].[EmployeeID] IS NULL AND [o0].[EmployeeID] IS NULL)) THEN CAST(1 AS bit)
ELSE CAST(0 AS bit)
END AS [HasOrders], COUNT(CASE
WHEN [c].[City] = N'London' THEN 1
END) AS [Londons]
FROM [Orders] AS [o]
LEFT JOIN [Customers] AS [c] ON [o].[CustomerID] = [c].[CustomerID]
GROUP BY [o].[EmployeeID]
""");
}

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

AssertSql(
"""
SELECT [o].[EmployeeID] AS [Key], CASE
WHEN NOT EXISTS (
SELECT 1
FROM [Orders] AS [o0]
WHERE ([o].[EmployeeID] = [o0].[EmployeeID] OR ([o].[EmployeeID] IS NULL AND [o0].[EmployeeID] IS NULL)) AND [o0].[OrderID] <= 10250) THEN CAST(1 AS bit)
ELSE CAST(0 AS bit)
END AS [AllLate], COUNT(CASE
WHEN [c].[City] = N'London' THEN 1
END) AS [Londons]
FROM [Orders] AS [o]
LEFT JOIN [Customers] AS [c] ON [o].[CustomerID] = [c].[CustomerID]
GROUP BY [o].[EmployeeID]
""");
}

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

AssertSql(
"""
SELECT [o].[EmployeeID] AS [Key], MAX([c].[Region]) AS [Region], CASE
WHEN EXISTS (
SELECT 1
FROM [Orders] AS [o0]
LEFT JOIN [Customers] AS [c0] ON [o0].[CustomerID] = [c0].[CustomerID]
WHERE ([o].[EmployeeID] = [o0].[EmployeeID] OR ([o].[EmployeeID] IS NULL AND [o0].[EmployeeID] IS NULL)) AND [c0].[City] = N'London') THEN CAST(1 AS bit)
ELSE CAST(0 AS bit)
END AS [AnyLondon], CASE
WHEN NOT EXISTS (
SELECT 1
FROM [Orders] AS [o1]
LEFT JOIN [Customers] AS [c1] ON [o1].[CustomerID] = [c1].[CustomerID]
WHERE ([o].[EmployeeID] = [o1].[EmployeeID] OR ([o].[EmployeeID] IS NULL AND [o1].[EmployeeID] IS NULL)) AND ([c1].[City] <> N'London' OR [c1].[City] IS NULL)) THEN CAST(1 AS bit)
ELSE CAST(0 AS bit)
END AS [AllLondon], COUNT(*) AS [Count]
FROM [Orders] AS [o]
LEFT JOIN [Customers] AS [c] ON [o].[CustomerID] = [c].[CustomerID]
GROUP BY [o].[EmployeeID]
""");
}

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

AssertSql(
"""
SELECT [o].[ProductID] AS [Key], CASE
WHEN EXISTS (
SELECT 1
FROM [Order Details] AS [o0]
INNER JOIN [Orders] AS [o1] ON [o0].[OrderID] = [o1].[OrderID]
LEFT JOIN [Customers] AS [c] ON [o1].[CustomerID] = [c].[CustomerID]
WHERE [o].[ProductID] = [o0].[ProductID] AND [c].[City] = N'London') THEN CAST(1 AS bit)
ELSE CAST(0 AS bit)
END AS [Londons]
FROM [Order Details] AS [o]
GROUP BY [o].[ProductID]
""");
}

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

AssertSql(
"""
SELECT [c].[City] AS [Key], CASE
WHEN EXISTS (
SELECT 1
FROM [Orders] AS [o0]
LEFT JOIN [Customers] AS [c0] ON [o0].[CustomerID] = [c0].[CustomerID]
WHERE ([c].[City] = [c0].[City] OR ([c].[City] IS NULL AND [c0].[City] IS NULL)) AND [c0].[City] = N'London') THEN CAST(1 AS bit)
ELSE CAST(0 AS bit)
END AS [Londons]
FROM [Orders] AS [o]
LEFT JOIN [Customers] AS [c] ON [o].[CustomerID] = [c].[CustomerID]
GROUP BY [c].[City]
""");
}

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

AssertSql(
"""
SELECT [o].[EmployeeID] AS [Key], CASE
WHEN EXISTS (
SELECT 1
FROM [Orders] AS [o0]
LEFT JOIN [Customers] AS [c] ON [o0].[CustomerID] = [c].[CustomerID]
WHERE ([o].[EmployeeID] = [o0].[EmployeeID] OR ([o].[EmployeeID] IS NULL AND [o0].[EmployeeID] IS NULL)) AND [c].[City] = N'London') THEN CAST(1 AS bit)
ELSE CAST(0 AS bit)
END AS [Londons]
FROM [Orders] AS [o]
GROUP BY [o].[EmployeeID]
""");
}

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