From fb8ccae1e5c7165dedc2cfedb46af50cfea17ca8 Mon Sep 17 00:00:00 2001 From: Shay Rojansky Date: Fri, 27 Dec 2019 18:28:29 +0100 Subject: [PATCH] Integrate comments by @smitpatel into source See https://github.com/aspnet/EntityFrameworkCore/issues/18874#issuecomment-553138737 --- ...ingExpressionVisitor.ExpressionVisitors.cs | 23 ++++++++++++++++++ ...nExpandingExpressionVisitor.Expressions.cs | 24 +++++++++++++++++++ 2 files changed, 47 insertions(+) diff --git a/src/EFCore/Query/Internal/NavigationExpandingExpressionVisitor.ExpressionVisitors.cs b/src/EFCore/Query/Internal/NavigationExpandingExpressionVisitor.ExpressionVisitors.cs index 284290a72d4..a92c7062503 100644 --- a/src/EFCore/Query/Internal/NavigationExpandingExpressionVisitor.ExpressionVisitors.cs +++ b/src/EFCore/Query/Internal/NavigationExpandingExpressionVisitor.ExpressionVisitors.cs @@ -15,6 +15,10 @@ namespace Microsoft.EntityFrameworkCore.Query.Internal { public partial class NavigationExpandingExpressionVisitor { + /// + /// Expands navigations in the given tree for given source. + /// Optionally also expands navigations for includes. + /// private class ExpandingExpressionVisitor : ExpressionVisitor { private readonly NavigationExpandingExpressionVisitor _navigationExpandingExpressionVisitor; @@ -308,6 +312,10 @@ protected Expression ExpandNavigation( } } + /// + /// Expands an include tree. This is separate and needed because we may need to reconstruct parts of + /// to apply includes. + /// private sealed class IncludeExpandingExpressionVisitor : ExpandingExpressionVisitor { private readonly bool _isTracking; @@ -534,6 +542,10 @@ private Expression ExpandIncludesHelper(Expression root, EntityReference entityR } } + /// + /// remembers the pending selector so we don't expand + /// navigations unless we need to. This visitor applies them when we need to. + /// private sealed class PendingSelectorExpandingExpressionVisitor : ExpressionVisitor { private readonly NavigationExpandingExpressionVisitor _visitor; @@ -566,6 +578,9 @@ public override Expression Visit(Expression expression) } } + /// + /// Removes custom expressions from tree and converts it to LINQ again. + /// private sealed class ReducingExpressionVisitor : ExpressionVisitor { public override Expression Visit(Expression expression) @@ -628,6 +643,11 @@ public override Expression Visit(Expression expression) } } + /// + /// Marks as nullable when coming from a left join. + /// Nullability is required to figure out if the navigation from this entity should be a left join or + /// an inner join. + /// private sealed class EntityReferenceOptionalMarkingExpressionVisitor : ExpressionVisitor { public override Expression Visit(Expression expression) @@ -643,6 +663,9 @@ public override Expression Visit(Expression expression) } } + /// + /// Allows self reference of query root inside query filters/defining queries. + /// private sealed class SelfReferenceEntityQueryableRewritingExpressionVisitor : ExpressionVisitor { private readonly NavigationExpandingExpressionVisitor _navigationExpandingExpressionVisitor; diff --git a/src/EFCore/Query/Internal/NavigationExpandingExpressionVisitor.Expressions.cs b/src/EFCore/Query/Internal/NavigationExpandingExpressionVisitor.Expressions.cs index aafaa8fe2d5..1b2dbc56129 100644 --- a/src/EFCore/Query/Internal/NavigationExpandingExpressionVisitor.Expressions.cs +++ b/src/EFCore/Query/Internal/NavigationExpandingExpressionVisitor.Expressions.cs @@ -76,6 +76,9 @@ public virtual void Print(ExpressionPrinter expressionPrinter) } } + /// + /// A tree structure of includes for a given entity type in . + /// protected class IncludeTreeNode : Dictionary { private EntityReference _entityReference; @@ -160,6 +163,10 @@ private bool Equals(IncludeTreeNode includeTreeNode) public override int GetHashCode() => HashCode.Combine(base.GetHashCode(), EntityType); } + /// + /// Stores information about the current queryable, its source, structure of projection, parameter type etc. + /// This is needed because once navigations are expanded we still remember these to avoid expanding again. + /// protected class NavigationExpansionExpression : Expression, IPrintableExpression { private readonly List<(MethodInfo OrderingMethod, Expression KeySelector)> _pendingOrderings @@ -248,6 +255,11 @@ public virtual void Print(ExpressionPrinter expressionPrinter) } } + /// + /// A leaf node on navigation tree, representing projection structures of + /// . Contains , + /// which can be or . + /// protected class NavigationTreeExpression : NavigationTreeNode, IPrintableExpression { public NavigationTreeExpression(Expression value) @@ -256,6 +268,9 @@ public NavigationTreeExpression(Expression value) Value = value; } + /// + /// Either or . + /// public virtual Expression Value { get; private set; } protected override Expression VisitChildren(ExpressionVisitor visitor) @@ -285,6 +300,11 @@ public virtual void Print(ExpressionPrinter expressionPrinter) } } + /// + /// A node in navigation binary tree. A navigation tree is a structure of the current parameter, which + /// would be transparent identifier (hence it's a binary structure). This allows us to easily condense to + /// inner/outer member access. + /// protected class NavigationTreeNode : Expression { private NavigationTreeNode _parent; @@ -333,6 +353,10 @@ public virtual Expression GetExpression() } } + /// + /// Owned navigations are not expanded, since they map differently in different providers. + /// This remembers such references so that they can still be treated like navigations. + /// protected class OwnedNavigationReference : Expression { public OwnedNavigationReference(Expression parent, INavigation navigation, EntityReference entityReference)