-
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
Redo query column/table relationship without TableReferenceExpression #32812
Conversation
{ | ||
table = joinExpressionBase.Table; | ||
} | ||
else if (table is SetOperationBase setOperationBase) |
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.
@maumar unless I'm mistaken, there was a bug here when a set operation was wrapped in a join; we'd unwrap the join above but not go into the set operation because of the "else" here.
@@ -2139,6 +2144,11 @@ public IReadOnlyDictionary<(TableExpressionBase, string), RelationalTypeMapping? | |||
|
|||
protected override Expression VisitExtension(Expression node) | |||
{ | |||
if (node is TableExpressionBase { Alias: string tableAlias } table) |
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.
This is one of the few examples of a visitor which really does need to go from columns to tables, and so maintains a table map during visitation.
// TODO: recreating a new TableExpressionBase implementation with a different alias. | ||
// TODO: Either add a mandatory, abstract non-destructive ChangeAlias to TableExpressionBase, or ideally, | ||
// TODO: refactor things to split the alias out of TableExpressionBase altogether. | ||
table.Alias = newAlias; |
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.
Note that TableExpressionBase.Alias is still mutable. It will be made immutable in a separate PR.
@@ -13,55 +13,85 @@ namespace Microsoft.EntityFrameworkCore.Query.SqlExpressions; | |||
/// </para> | |||
/// </summary> | |||
[DebuggerDisplay("{TableAlias}.{Name}")] | |||
public abstract class ColumnExpression : SqlExpression | |||
public class ColumnExpression : SqlExpression |
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.
Note that ColumnExpression is no longer abstract, with a private ConcreteColumnExpression that only SelectExpression can construct. This is now a plain, regular SqlExpression that anyone can build.
{ | ||
if (_mutable) | ||
{ | ||
VisitList(_tables, inPlace: true, out _); |
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.
Note that table visitation has been moved to be the first. This aligns with actual evaluation order of SQL SELECT - tables are evaluated first, and projections last - they can reference tables (the textual layout of SQL SELECT has always seemed like a mistake; IDEs can't to Intellisense as the user is writing projections since the tables haven't been written yet... Note that in C# LINQ expression syntax the tables come first).
This is a more useful for visitors which need to visit tables first, for tracking purposes etc.
// Otherwise, if no tables have changed, we mutate the TableReferenceExpressions (this was the previous code, left it for | ||
// a more low-risk fix). Note that updateColumns is false only if we're already being called from | ||
// ColumnTableReferenceUpdater to replace the ColumnExpressions, in which case we avoid infinite recursion. | ||
if (tablesChanged && updateColumns) |
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.
All this table reference updating/cloning is now gone 🎉
/// </remarks> | ||
// TODO: Make this protected after SelectExpression.Prune is moved into this visitor | ||
[EntityFrameworkInternal] | ||
public virtual string? CurrentTableAlias { get; set; } |
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.
When everything is done, I plan to do a final cleanup here to move the SelectExpression.Prune functionailty into this visitor; at that point everything will be nice and self-contained. Right now it's somewhat smelly - that's a temporary situation.
b0607d0
to
767a4f2
Compare
/// </summary> | ||
[EntityFrameworkInternal] | ||
public virtual string GetRequiredAlias() | ||
=> Alias ?? throw new InvalidOperationException($"No alias is defined on table: {ExpressionPrinter.Print(this)}"); |
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.
add resource string
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.
Oops missed this one, will do in the #32815
src/EFCore.Relational/Query/RelationalQueryableMethodTranslatingExpressionVisitor.cs
Outdated
Show resolved
Hide resolved
767a4f2
to
37d9118
Compare
37d9118
to
ac176a4
Compare
NOTE: THIS IS BASED ON TOP OF #32785 (ALIAS REDO), REVIEW ONLY THE 2ND COMMITCloses #32558