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: Expand navigations after GroupBy operator is applied #22609

Closed
Tracked by #24106
smitpatel opened this issue Sep 18, 2020 · 1 comment · Fixed by #25495
Closed
Tracked by #24106

Query: Expand navigations after GroupBy operator is applied #22609

smitpatel opened this issue Sep 18, 2020 · 1 comment · Fixed by #25495
Assignees
Labels
area-query closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. ef6-parity type-enhancement
Milestone

Comments

@smitpatel
Copy link
Contributor

The Joins for navigations need to be applied before calling GroupBy which makes it complicated.

@mhosman
Copy link

mhosman commented May 6, 2021

Same issue here. Im stuck with this one.

smitpatel added a commit that referenced this issue Aug 12, 2021
- Allow expanding navigations after GroupBy operator applied before reducing it to non-grouping Fixes #22609
- Translate FirstOrDefault over grouping element Fixes #12088
- Add ability to select N element over grouping element Fixes #13805

Overall approach:
A grouping element (the range variable you get after applying GroupBy operator) is of type `IGrouping<TKey, TElement>` which implements `IEnumerable<TElement>`. Hence we treat this enumerable as if it is queryable during nav expansion phase. During translation phase we inject ShapedQueryExpression in place of the grouping element which is being enumerated. What this allows us is to expand navigation just like any other query root and translate a subquery similar to other subqueries to facilitate reusing same code for the tasks.
During translation phase in relational layer, since aggregate operation can be lifted into projection for SelectExpression containing SQL GROUP BY. This code path works in 2 ways, when translating we try to combine predicate/distinct into the aggregate operation (so in future when we support custom aggregate operators, we don't have to understand the shape of it to modify it later. When adding this scalar subquery to SelectExpression, we try to pattern match it to see if we can lift it. Further during lifting, we also lift any additional joins in the subquery (which implies there were some joins expanded on grouping element before aggregate) including the navigation expanded from owned navigations. A pending TODO is to de-dupe navigation expanded. It is not straight forward since aliases of table would have changed when previous was lifted.
Given every enumerable grouping element act as query root, every time we replace it inside a lambda expression, we need to create a copy of the root. Navigation expansion and individual queryableMethodTranslatingEV does this. So each root act and translate independently from each other.

Bug fixes:
- Fix a bug in identifying single result in InMemory to convert it to enumerable
- Null out _groupingParameter in InMemoryQueryExpression once the projection to reduce it has been applied
- Throw better error message when translating Min/Max over an entity type for InMemory
@smitpatel smitpatel added the closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. label Aug 12, 2021
smitpatel added a commit that referenced this issue Aug 12, 2021
- Allow expanding navigations after GroupBy operator applied before reducing it to non-grouping Fixes #22609
- Translate FirstOrDefault over grouping element Fixes #12088
- Add ability to select N element over grouping element Fixes #13805

Overall approach:
A grouping element (the range variable you get after applying GroupBy operator) is of type `IGrouping<TKey, TElement>` which implements `IEnumerable<TElement>`. Hence we treat this enumerable as if it is queryable during nav expansion phase. During translation phase we inject ShapedQueryExpression in place of the grouping element which is being enumerated. What this allows us is to expand navigation just like any other query root and translate a subquery similar to other subqueries to facilitate reusing same code for the tasks.
During translation phase in relational layer, since aggregate operation can be lifted into projection for SelectExpression containing SQL GROUP BY. This code path works in 2 ways, when translating we try to combine predicate/distinct into the aggregate operation (so in future when we support custom aggregate operators, we don't have to understand the shape of it to modify it later. When adding this scalar subquery to SelectExpression, we try to pattern match it to see if we can lift it. Further during lifting, we also lift any additional joins in the subquery (which implies there were some joins expanded on grouping element before aggregate) including the navigation expanded from owned navigations. A pending TODO is to de-dupe navigation expanded. It is not straight forward since aliases of table would have changed when previous was lifted.
Given every enumerable grouping element act as query root, every time we replace it inside a lambda expression, we need to create a copy of the root. Navigation expansion and individual queryableMethodTranslatingEV does this. So each root act and translate independently from each other.

Bug fixes:
- Fix a bug in identifying single result in InMemory to convert it to enumerable
- Null out _groupingParameter in InMemoryQueryExpression once the projection to reduce it has been applied
- Throw better error message when translating Min/Max over an entity type for InMemory
smitpatel added a commit that referenced this issue Aug 12, 2021
- Allow expanding navigations after GroupBy operator applied before reducing it to non-grouping Fixes #22609
- Translate FirstOrDefault over grouping element Fixes #12088
- Add ability to select N element over grouping element Fixes #13805

Overall approach:
A grouping element (the range variable you get after applying GroupBy operator) is of type `IGrouping<TKey, TElement>` which implements `IEnumerable<TElement>`. Hence we treat this enumerable as if it is queryable during nav expansion phase. During translation phase we inject ShapedQueryExpression in place of the grouping element which is being enumerated. What this allows us is to expand navigation just like any other query root and translate a subquery similar to other subqueries to facilitate reusing same code for the tasks.
During translation phase in relational layer, since aggregate operation can be lifted into projection for SelectExpression containing SQL GROUP BY. This code path works in 2 ways, when translating we try to combine predicate/distinct into the aggregate operation (so in future when we support custom aggregate operators, we don't have to understand the shape of it to modify it later. When adding this scalar subquery to SelectExpression, we try to pattern match it to see if we can lift it. Further during lifting, we also lift any additional joins in the subquery (which implies there were some joins expanded on grouping element before aggregate) including the navigation expanded from owned navigations. A pending TODO is to de-dupe navigation expanded. It is not straight forward since aliases of table would have changed when previous was lifted.
Given every enumerable grouping element act as query root, every time we replace it inside a lambda expression, we need to create a copy of the root. Navigation expansion and individual queryableMethodTranslatingEV does this. So each root act and translate independently from each other.

Bug fixes:
- Fix a bug in identifying single result in InMemory to convert it to enumerable
- Null out _groupingParameter in InMemoryQueryExpression once the projection to reduce it has been applied
- Throw better error message when translating Min/Max over an entity type for InMemory
smitpatel added a commit that referenced this issue Aug 13, 2021
- Allow expanding navigations after GroupBy operator applied before reducing it to non-grouping Fixes #22609
- Translate FirstOrDefault over grouping element Fixes #12088
- Add ability to select N element over grouping element Fixes #13805

Overall approach:
A grouping element (the range variable you get after applying GroupBy operator) is of type `IGrouping<TKey, TElement>` which implements `IEnumerable<TElement>`. Hence we treat this enumerable as if it is queryable during nav expansion phase. During translation phase we inject ShapedQueryExpression in place of the grouping element which is being enumerated. What this allows us is to expand navigation just like any other query root and translate a subquery similar to other subqueries to facilitate reusing same code for the tasks.
During translation phase in relational layer, since aggregate operation can be lifted into projection for SelectExpression containing SQL GROUP BY. This code path works in 2 ways, when translating we try to combine predicate/distinct into the aggregate operation (so in future when we support custom aggregate operators, we don't have to understand the shape of it to modify it later. When adding this scalar subquery to SelectExpression, we try to pattern match it to see if we can lift it. Further during lifting, we also lift any additional joins in the subquery (which implies there were some joins expanded on grouping element before aggregate) including the navigation expanded from owned navigations. A pending TODO is to de-dupe navigation expanded. It is not straight forward since aliases of table would have changed when previous was lifted.
Given every enumerable grouping element act as query root, every time we replace it inside a lambda expression, we need to create a copy of the root. Navigation expansion and individual queryableMethodTranslatingEV does this. So each root act and translate independently from each other.

Bug fixes:
- Fix a bug in identifying single result in InMemory to convert it to enumerable
- Null out _groupingParameter in InMemoryQueryExpression once the projection to reduce it has been applied
- Throw better error message when translating Min/Max over an entity type for InMemory
smitpatel added a commit that referenced this issue Aug 16, 2021
- Allow expanding navigations after GroupBy operator applied before reducing it to non-grouping Fixes #22609
- Translate FirstOrDefault over grouping element Fixes #12088
- Add ability to select N element over grouping element Fixes #13805

Overall approach:
A grouping element (the range variable you get after applying GroupBy operator) is of type `IGrouping<TKey, TElement>` which implements `IEnumerable<TElement>`. Hence we treat this enumerable as if it is queryable during nav expansion phase. During translation phase we inject ShapedQueryExpression in place of the grouping element which is being enumerated. What this allows us is to expand navigation just like any other query root and translate a subquery similar to other subqueries to facilitate reusing same code for the tasks.
During translation phase in relational layer, since aggregate operation can be lifted into projection for SelectExpression containing SQL GROUP BY. This code path works in 2 ways, when translating we try to combine predicate/distinct into the aggregate operation (so in future when we support custom aggregate operators, we don't have to understand the shape of it to modify it later. When adding this scalar subquery to SelectExpression, we try to pattern match it to see if we can lift it. Further during lifting, we also lift any additional joins in the subquery (which implies there were some joins expanded on grouping element before aggregate) including the navigation expanded from owned navigations. A pending TODO is to de-dupe navigation expanded. It is not straight forward since aliases of table would have changed when previous was lifted.
Given every enumerable grouping element act as query root, every time we replace it inside a lambda expression, we need to create a copy of the root. Navigation expansion and individual queryableMethodTranslatingEV does this. So each root act and translate independently from each other.

Bug fixes:
- Fix a bug in identifying single result in InMemory to convert it to enumerable
- Null out _groupingParameter in InMemoryQueryExpression once the projection to reduce it has been applied
- Throw better error message when translating Min/Max over an entity type for InMemory
smitpatel added a commit that referenced this issue Aug 16, 2021
- Allow expanding navigations after GroupBy operator applied before reducing it to non-grouping Fixes #22609
- Translate FirstOrDefault over grouping element Fixes #12088
- Add ability to select N element over grouping element Fixes #13805

Overall approach:
A grouping element (the range variable you get after applying GroupBy operator) is of type `IGrouping<TKey, TElement>` which implements `IEnumerable<TElement>`. Hence we treat this enumerable as if it is queryable during nav expansion phase. During translation phase we inject ShapedQueryExpression in place of the grouping element which is being enumerated. What this allows us is to expand navigation just like any other query root and translate a subquery similar to other subqueries to facilitate reusing same code for the tasks.
During translation phase in relational layer, since aggregate operation can be lifted into projection for SelectExpression containing SQL GROUP BY. This code path works in 2 ways, when translating we try to combine predicate/distinct into the aggregate operation (so in future when we support custom aggregate operators, we don't have to understand the shape of it to modify it later. When adding this scalar subquery to SelectExpression, we try to pattern match it to see if we can lift it. Further during lifting, we also lift any additional joins in the subquery (which implies there were some joins expanded on grouping element before aggregate) including the navigation expanded from owned navigations. A pending TODO is to de-dupe navigation expanded. It is not straight forward since aliases of table would have changed when previous was lifted.
Given every enumerable grouping element act as query root, every time we replace it inside a lambda expression, we need to create a copy of the root. Navigation expansion and individual queryableMethodTranslatingEV does this. So each root act and translate independently from each other.

Bug fixes:
- Fix a bug in identifying single result in InMemory to convert it to enumerable
- Null out _groupingParameter in InMemoryQueryExpression once the projection to reduce it has been applied
- Throw better error message when translating Min/Max over an entity type for InMemory
@ghost ghost closed this as completed in #25495 Aug 17, 2021
ghost pushed a commit that referenced this issue Aug 17, 2021
- Allow expanding navigations after GroupBy operator applied before reducing it to non-grouping Fixes #22609
- Translate FirstOrDefault over grouping element Fixes #12088
- Add ability to select N element over grouping element Fixes #13805

Overall approach:
A grouping element (the range variable you get after applying GroupBy operator) is of type `IGrouping<TKey, TElement>` which implements `IEnumerable<TElement>`. Hence we treat this enumerable as if it is queryable during nav expansion phase. During translation phase we inject ShapedQueryExpression in place of the grouping element which is being enumerated. What this allows us is to expand navigation just like any other query root and translate a subquery similar to other subqueries to facilitate reusing same code for the tasks.
During translation phase in relational layer, since aggregate operation can be lifted into projection for SelectExpression containing SQL GROUP BY. This code path works in 2 ways, when translating we try to combine predicate/distinct into the aggregate operation (so in future when we support custom aggregate operators, we don't have to understand the shape of it to modify it later. When adding this scalar subquery to SelectExpression, we try to pattern match it to see if we can lift it. Further during lifting, we also lift any additional joins in the subquery (which implies there were some joins expanded on grouping element before aggregate) including the navigation expanded from owned navigations. A pending TODO is to de-dupe navigation expanded. It is not straight forward since aliases of table would have changed when previous was lifted.
Given every enumerable grouping element act as query root, every time we replace it inside a lambda expression, we need to create a copy of the root. Navigation expansion and individual queryableMethodTranslatingEV does this. So each root act and translate independently from each other.

Bug fixes:
- Fix a bug in identifying single result in InMemory to convert it to enumerable
- Null out _groupingParameter in InMemoryQueryExpression once the projection to reduce it has been applied
- Throw better error message when translating Min/Max over an entity type for InMemory
@ajcvickers ajcvickers modified the milestones: 6.0.0, 6.0.0-rc1 Aug 17, 2021
@ajcvickers ajcvickers modified the milestones: 6.0.0-rc1, 6.0.0 Nov 8, 2021
This issue was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-query closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. ef6-parity type-enhancement
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants