-
Notifications
You must be signed in to change notification settings - Fork 3.2k
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: Support for GroupBy entity type #29019
Merged
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -109,11 +109,18 @@ public virtual Task GroupBy_is_optimized_when_grouping_by_row_and_projecting_col | |||||
[ConditionalTheory] | ||||||
[MemberData(nameof(IsAsyncData))] | ||||||
public virtual Task Grouping_by_all_columns_doesnt_produce_a_groupby_statement(bool async) | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit:
Suggested change
|
||||||
// GroupBy entityType. Issue #17653. | ||||||
=> AssertTranslationFailed( | ||||||
() => AssertQuery( | ||||||
async, | ||||||
ss => ss.Set<ArubaOwner>().GroupBy(o => o).Select(g => g.Key))); | ||||||
=> AssertQuery( | ||||||
async, | ||||||
ss => ss.Set<ArubaOwner>().GroupBy(o => o).Select(g => g.Key), | ||||||
elementSorter: e => e.Id, | ||||||
elementAsserter: (e, a) => | ||||||
{ | ||||||
Assert.Equal(e.Id, a.Id); | ||||||
Assert.Equal(e.Alias, a.Alias); | ||||||
Assert.Equal(e.FirstName, a.FirstName); | ||||||
Assert.Equal(e.LastName, a.LastName); | ||||||
}, | ||||||
entryCount: 10); | ||||||
|
||||||
[ConditionalTheory] | ||||||
[MemberData(nameof(IsAsyncData))] | ||||||
|
@@ -132,111 +139,93 @@ public virtual Task Grouping_by_all_columns_with_aggregate_function_works_1(bool | |||||
[ConditionalTheory] | ||||||
[MemberData(nameof(IsAsyncData))] | ||||||
public virtual Task Grouping_by_all_columns_with_aggregate_function_works_2(bool async) | ||||||
// GroupBy entityType. Issue #17653. | ||||||
=> AssertTranslationFailed( | ||||||
() => AssertQueryScalar( | ||||||
async, | ||||||
ss => ss.Set<ArubaOwner>().GroupBy(o => o, c => new { c.LastName, c.FirstName }, (k, g) => g.Count()))); | ||||||
=> AssertQueryScalar( | ||||||
async, | ||||||
ss => ss.Set<ArubaOwner>().GroupBy(o => o, c => new { c.LastName, c.FirstName }, (k, g) => g.Count())); | ||||||
|
||||||
[ConditionalTheory] | ||||||
[MemberData(nameof(IsAsyncData))] | ||||||
public virtual Task Grouping_by_all_columns_with_aggregate_function_works_3(bool async) | ||||||
// GroupBy entityType. Issue #17653. | ||||||
=> AssertTranslationFailed( | ||||||
() => AssertQueryScalar( | ||||||
async, | ||||||
ss => ss.Set<ArubaOwner>().GroupBy(o => o, c => c, (k, g) => g.Count()))); | ||||||
=> AssertQueryScalar( | ||||||
async, | ||||||
ss => ss.Set<ArubaOwner>().GroupBy(o => o, c => c, (k, g) => g.Count())); | ||||||
|
||||||
[ConditionalTheory] | ||||||
[MemberData(nameof(IsAsyncData))] | ||||||
public virtual Task Grouping_by_all_columns_with_aggregate_function_works_4(bool async) | ||||||
// GroupBy entityType. Issue #17653. | ||||||
=> AssertTranslationFailed( | ||||||
() => AssertQuery( | ||||||
async, | ||||||
ss => ss.Set<ArubaOwner>().GroupBy(o => o, c => c, (k, g) => new { Count = g.Count() }))); | ||||||
=> AssertQuery( | ||||||
async, | ||||||
ss => ss.Set<ArubaOwner>().GroupBy(o => o, c => c, (k, g) => new { Count = g.Count() })); | ||||||
|
||||||
[ConditionalTheory] | ||||||
[MemberData(nameof(IsAsyncData))] | ||||||
public virtual Task Grouping_by_all_columns_with_aggregate_function_works_5(bool async) | ||||||
// GroupBy entityType. Issue #17653. | ||||||
=> AssertTranslationFailed( | ||||||
() => AssertQuery( | ||||||
async, | ||||||
ss => ss.Set<ArubaOwner>().GroupBy(o => o, c => c, (k, g) => new { k.Id, Count = g.Count() }))); | ||||||
=> AssertQuery( | ||||||
async, | ||||||
ss => ss.Set<ArubaOwner>().GroupBy(o => o, c => c, (k, g) => new { k.Id, Count = g.Count() })); | ||||||
|
||||||
[ConditionalTheory] | ||||||
[MemberData(nameof(IsAsyncData))] | ||||||
public virtual Task Grouping_by_all_columns_with_aggregate_function_works_6(bool async) | ||||||
// GroupBy entityType. Issue #17653. | ||||||
=> AssertTranslationFailed( | ||||||
() => AssertQuery( | ||||||
async, | ||||||
ss => ss.Set<ArubaOwner>().GroupBy( | ||||||
o => o, c => c, (k, g) => new | ||||||
{ | ||||||
k.Id, | ||||||
k.Alias, | ||||||
Count = g.Count() | ||||||
}))); | ||||||
=> AssertQuery( | ||||||
async, | ||||||
ss => ss.Set<ArubaOwner>().GroupBy( | ||||||
o => o, c => c, (k, g) => new | ||||||
{ | ||||||
k.Id, | ||||||
k.Alias, | ||||||
Count = g.Count() | ||||||
})); | ||||||
|
||||||
[ConditionalTheory] | ||||||
[MemberData(nameof(IsAsyncData))] | ||||||
public virtual Task Grouping_by_all_columns_with_aggregate_function_works_7(bool async) | ||||||
// GroupBy entityType. Issue #17653. | ||||||
=> AssertTranslationFailed( | ||||||
() => AssertQueryScalar( | ||||||
async, | ||||||
ss => from o in ss.Set<ArubaOwner>() | ||||||
group o by o | ||||||
into g | ||||||
select g.Count())); | ||||||
=> AssertQueryScalar( | ||||||
async, | ||||||
ss => from o in ss.Set<ArubaOwner>() | ||||||
group o by o | ||||||
into g | ||||||
select g.Count()); | ||||||
|
||||||
[ConditionalTheory] | ||||||
[MemberData(nameof(IsAsyncData))] | ||||||
public virtual Task Grouping_by_all_columns_with_aggregate_function_works_8(bool async) | ||||||
// GroupBy entityType. Issue #17653. | ||||||
=> AssertTranslationFailed( | ||||||
() => AssertQuery( | ||||||
async, | ||||||
ss => from o in ss.Set<ArubaOwner>() | ||||||
group o by o | ||||||
into g | ||||||
select new { g.Key.Id, Count = g.Count() })); | ||||||
=> AssertQuery( | ||||||
async, | ||||||
ss => from o in ss.Set<ArubaOwner>() | ||||||
group o by o | ||||||
into g | ||||||
select new { g.Key.Id, Count = g.Count() }); | ||||||
|
||||||
[ConditionalTheory] | ||||||
[MemberData(nameof(IsAsyncData))] | ||||||
public virtual Task Grouping_by_all_columns_with_aggregate_function_works_9(bool async) | ||||||
// GroupBy entityType. Issue #17653. | ||||||
=> AssertTranslationFailed( | ||||||
() => AssertQuery( | ||||||
async, | ||||||
ss => from o in ss.Set<ArubaOwner>() | ||||||
group o by o | ||||||
into g | ||||||
select new | ||||||
{ | ||||||
g.Key.Id, | ||||||
g.Key.Alias, | ||||||
Count = g.Count() | ||||||
})); | ||||||
=> AssertQuery( | ||||||
async, | ||||||
ss => from o in ss.Set<ArubaOwner>() | ||||||
group o by o | ||||||
into g | ||||||
select new | ||||||
{ | ||||||
g.Key.Id, | ||||||
g.Key.Alias, | ||||||
Count = g.Count() | ||||||
}); | ||||||
|
||||||
[ConditionalTheory] | ||||||
[MemberData(nameof(IsAsyncData))] | ||||||
public virtual Task Grouping_by_all_columns_with_aggregate_function_works_10(bool async) | ||||||
// GroupBy entityType. Issue #17653. | ||||||
=> AssertTranslationFailed( | ||||||
() => AssertQuery( | ||||||
async, | ||||||
ss => from o in ss.Set<ArubaOwner>() | ||||||
group o by o | ||||||
into g | ||||||
select new | ||||||
{ | ||||||
g.Key.Id, | ||||||
Sum = g.Sum(x => x.Id), | ||||||
Count = g.Count() | ||||||
})); | ||||||
=> AssertQuery( | ||||||
async, | ||||||
ss => from o in ss.Set<ArubaOwner>() | ||||||
group o by o | ||||||
into g | ||||||
select new | ||||||
{ | ||||||
g.Key.Id, | ||||||
Sum = g.Sum(x => x.Id), | ||||||
Count = g.Count() | ||||||
}); | ||||||
|
||||||
[ConditionalTheory] | ||||||
[MemberData(nameof(IsAsyncData))] | ||||||
|
@@ -731,7 +720,6 @@ public virtual Task Whats_new_2021_sample_13(bool async) | |||||
[ConditionalTheory] // From #12088 | ||||||
[MemberData(nameof(IsAsyncData))] | ||||||
public virtual Task Whats_new_2021_sample_14(bool async) | ||||||
// GroupBy entityType. Issue #17653. | ||||||
=> AssertTranslationFailed( | ||||||
() => AssertQuery( | ||||||
async, | ||||||
|
@@ -742,13 +730,12 @@ public virtual Task Whats_new_2021_sample_14(bool async) | |||||
[ConditionalTheory] // From #12088 | ||||||
[MemberData(nameof(IsAsyncData))] | ||||||
public virtual Task Whats_new_2021_sample_15(bool async) | ||||||
// GroupBy entityType. Issue #17653. | ||||||
=> AssertTranslationFailed( | ||||||
() => AssertQuery( | ||||||
async, | ||||||
ss => ss.Set<Person>() | ||||||
.GroupBy(bp => bp.Feet) | ||||||
.Select(g => g.OrderByDescending(bp => bp.Id).FirstOrDefault()))); | ||||||
=> AssertQuery( | ||||||
async, | ||||||
ss => ss.Set<Person>() | ||||||
.GroupBy(bp => bp.Feet) | ||||||
.Select(g => g.OrderByDescending(bp => bp.Id).FirstOrDefault()), | ||||||
entryCount: 12); | ||||||
|
||||||
[ConditionalTheory] // From #12573 | ||||||
[MemberData(nameof(IsAsyncData))] | ||||||
|
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So if I understand correctly, we're opting for grouping by all the entity type's properties, as opposed to grouping by its primary key properties (I can see some discussion in #17653).
Wouldn't grouping by the primary key be potentially much more efficient (I can do some quick benchmarking)? On the hand, I understand that in some databases we'd need to use a trick such as MAX() in order to project out the other properties...
BTW what happens with keyless entities, where two rows may have the same property values and therefore get grouped together? Seems like we should block that no?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
EF6 did group by all properties so this implementation just aligns the behavior with that. The complexity of utilizing key in query after grouping is quite high, which questions why user is not writing group by PK in first place. Can improve it later.
For keyless entity, fine either way. 2 rows can get grouped together but change tracker has no behavior that they are same entities or different entities so neither behavior is wrong.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Re grouping by all properties, yeah, we can see about improving in the future. It's true the user can explicitly group by the primary key, but that can be said about the feature as a whole.. Specifically, if grouping by all properties is inefficient compared to grouping by primary key (will try to benchmark this), we may be doing users a disservice by providing a slower translation (and they wouldn't know about it) - a translation failure at least forces them to explicitly specify what they want to group by.
Re keyless, if our translation groups two rows together because all their properties are the same, isn't that different from the LINQ to Objects behavior which groups by the reference, and so never returns a group of two?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Comment by @smitpatel: we already compare all properties for the Distinct translation, so GroupBy is consistent with that here.