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

Add support for eager loaded navigations #16473

Merged
merged 1 commit into from
Jul 9, 2019
Merged
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 @@ -18,6 +18,7 @@
using Microsoft.EntityFrameworkCore.Metadata.Internal;
using Microsoft.EntityFrameworkCore.Query;
using Microsoft.EntityFrameworkCore.Query.Internal;
using Microsoft.EntityFrameworkCore.Query.NavigationExpansion;
using Microsoft.EntityFrameworkCore.Query.Pipeline;
using Microsoft.EntityFrameworkCore.Storage;
using Newtonsoft.Json.Linq;
Expand Down Expand Up @@ -169,77 +170,80 @@ protected override Expression VisitMethodCall(MethodCallExpression methodCallExp

protected override Expression VisitExtension(Expression extensionExpression)
{
if (extensionExpression is ProjectionBindingExpression projectionBindingExpression)
switch (extensionExpression)
{
var projectionIndex = (int)GetProjectionIndex(projectionBindingExpression);
var projection = _selectExpression.Projection[projectionIndex];

return CreateGetStoreValueExpression(
_jObjectParameter,
projection.Alias,
((SqlExpression)projection.Expression).TypeMapping,
projectionBindingExpression.Type);
}

if (extensionExpression is EntityShaperExpression shaperExpression)
{
_currentEntityIndex++;

var jObjectVariable = Expression.Variable(typeof(JObject),
"jObject" + _currentEntityIndex);
var variables = new List<ParameterExpression> { jObjectVariable };
case ProjectionBindingExpression projectionBindingExpression:
{
var projectionIndex = (int)GetProjectionIndex(projectionBindingExpression);
var projection = _selectExpression.Projection[projectionIndex];

return CreateGetStoreValueExpression(
_jObjectParameter,
projection.Alias,
((SqlExpression)projection.Expression).TypeMapping,
projectionBindingExpression.Type);
}

var expressions = new List<Expression>();
case EntityShaperExpression shaperExpression:
{
_currentEntityIndex++;

if (shaperExpression.ParentNavigation == null)
{
var projectionIndex = (int)GetProjectionIndex((ProjectionBindingExpression)shaperExpression.ValueBufferExpression);
var projection = _selectExpression.Projection[projectionIndex];
var jObjectVariable = Expression.Variable(typeof(JObject),
"jObject" + _currentEntityIndex);
var variables = new List<ParameterExpression> { jObjectVariable };

expressions.Add(
Expression.Assign(
jObjectVariable,
Expression.TypeAs(
CreateReadJTokenExpression(_jObjectParameter, projection.Alias),
typeof(JObject))));
var expressions = new List<Expression>();

shaperExpression = shaperExpression.Update(
shaperExpression.ValueBufferExpression,
GetNestedShapers(shaperExpression.EntityType, shaperExpression.ValueBufferExpression));
}
else
{
var methodCallExpression = (MethodCallExpression)shaperExpression.ValueBufferExpression;
Debug.Assert(methodCallExpression.Method.IsGenericMethod
&& methodCallExpression.Method.GetGenericMethodDefinition() == EntityMaterializerSource.TryReadValueMethod);

var navigation = (INavigation)((ConstantExpression)methodCallExpression.Arguments[2]).Value;

expressions.Add(
Expression.Assign(
jObjectVariable,
Expression.TypeAs(
CreateReadJTokenExpression(_jObjectParameter, navigation.GetTargetType().GetCosmosContainingPropertyName()),
typeof(JObject))));
}
if (shaperExpression.ParentNavigation == null)
{
var projectionIndex = (int)GetProjectionIndex((ProjectionBindingExpression)shaperExpression.ValueBufferExpression);
var projection = _selectExpression.Projection[projectionIndex];

expressions.Add(
Expression.Assign(
jObjectVariable,
Expression.TypeAs(
CreateReadJTokenExpression(_jObjectParameter, projection.Alias),
typeof(JObject))));

shaperExpression = shaperExpression.Update(
shaperExpression.ValueBufferExpression,
GetNestedShapers(shaperExpression.EntityType, shaperExpression.ValueBufferExpression));
}
else
{
var methodCallExpression = (MethodCallExpression)shaperExpression.ValueBufferExpression;
Debug.Assert(methodCallExpression.Method.IsGenericMethod
&& methodCallExpression.Method.GetGenericMethodDefinition() == EntityMaterializerSource.TryReadValueMethod);

var navigation = (INavigation)((ConstantExpression)methodCallExpression.Arguments[2]).Value;

expressions.Add(
Expression.Assign(
jObjectVariable,
Expression.TypeAs(
CreateReadJTokenExpression(_jObjectParameter, navigation.GetTargetType().GetCosmosContainingPropertyName()),
typeof(JObject))));
}

var parentJObject = _jObjectParameter;
_jObjectParameter = jObjectVariable;
expressions.Add(Expression.Condition(
Expression.Equal(jObjectVariable, Expression.Constant(null, jObjectVariable.Type)),
Expression.Constant(null, shaperExpression.Type),
Visit(_shapedQueryCompilingExpressionVisitor.InjectEntityMaterializer(shaperExpression))));
_jObjectParameter = parentJObject;

return Expression.Block(
shaperExpression.Type,
variables,
expressions);
}
var parentJObject = _jObjectParameter;
_jObjectParameter = jObjectVariable;
expressions.Add(Expression.Condition(
Expression.Equal(jObjectVariable, Expression.Constant(null, jObjectVariable.Type)),
Expression.Constant(null, shaperExpression.Type),
Visit(_shapedQueryCompilingExpressionVisitor.InjectEntityMaterializer(shaperExpression))));
_jObjectParameter = parentJObject;

return Expression.Block(
shaperExpression.Type,
variables,
expressions);
}

if (extensionExpression is CollectionShaperExpression collectionShaperExpression)
{
throw new NotImplementedException();
case CollectionShaperExpression collectionShaperExpression:
throw new NotImplementedException();
case IncludeExpression includeExpression:
return includeExpression;
}

return base.VisitExtension(extensionExpression);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,60 +81,51 @@ public override Expression Visit(Expression expression)

if (_clientEval)
{
if (expression is ConstantExpression)
switch (expression)
{
return expression;
}

if (expression is ParameterExpression parameterExpression)
{
return Expression.Call(
_getParameterValueMethodInfo.MakeGenericMethod(parameterExpression.Type),
QueryCompilationContext.QueryContextParameter,
Expression.Constant(parameterExpression.Name));
}

if (expression is MaterializeCollectionNavigationExpression materializeCollectionNavigationExpression)
{
return _selectExpression.AddCollectionProjection(
_queryableMethodTranslatingExpressionVisitor.TranslateSubquery(
case ConstantExpression _:
return expression;
case ParameterExpression parameterExpression:
return Expression.Call(
_getParameterValueMethodInfo.MakeGenericMethod(parameterExpression.Type),
QueryCompilationContext.QueryContextParameter,
Expression.Constant(parameterExpression.Name));
case MaterializeCollectionNavigationExpression materializeCollectionNavigationExpression:
return _selectExpression.AddCollectionProjection(
_queryableMethodTranslatingExpressionVisitor.TranslateSubquery(
materializeCollectionNavigationExpression.Subquery),
materializeCollectionNavigationExpression.Navigation, null);
}
materializeCollectionNavigationExpression.Navigation, null);
case MethodCallExpression methodCallExpression:
{
if (methodCallExpression.Method.IsGenericMethod
&& methodCallExpression.Method.DeclaringType == typeof(Enumerable)
&& methodCallExpression.Method.Name == nameof(Enumerable.ToList))
{
var elementType = methodCallExpression.Method.GetGenericArguments()[0];

if (expression is MethodCallExpression methodCallExpression)
{
if (methodCallExpression.Method.IsGenericMethod
&& methodCallExpression.Method.DeclaringType == typeof(Enumerable)
&& methodCallExpression.Method.Name == nameof(Enumerable.ToList))
{
var elementType = methodCallExpression.Method.GetGenericArguments()[0];
var result = _queryableMethodTranslatingExpressionVisitor.TranslateSubquery(methodCallExpression.Arguments[0]);

var result = _queryableMethodTranslatingExpressionVisitor.TranslateSubquery(methodCallExpression.Arguments[0]);
return _selectExpression.AddCollectionProjection(result, null, elementType);
}

return _selectExpression.AddCollectionProjection(result, null, elementType);
}
var subquery = _queryableMethodTranslatingExpressionVisitor.TranslateSubquery(methodCallExpression);

var subquery = _queryableMethodTranslatingExpressionVisitor.TranslateSubquery(methodCallExpression);
if (subquery != null)
{
if (subquery.ResultType == ResultType.Enumerable)
{
return _selectExpression.AddCollectionProjection(subquery, null, subquery.ShaperExpression.Type);
}
}

if (subquery != null)
{
if (subquery.ResultType == ResultType.Enumerable)
{
return _selectExpression.AddCollectionProjection(subquery, null, subquery.ShaperExpression.Type);
break;
}
}
}

var translation = _sqlTranslator.Translate(expression);
if (translation == null)
{
return base.Visit(expression);
}
else
{
return new ProjectionBindingExpression(_selectExpression, _selectExpression.AddToProjection(translation), expression.Type);
}
return translation == null
? base.Visit(expression)
: new ProjectionBindingExpression(_selectExpression, _selectExpression.AddToProjection(translation), expression.Type);
}
else
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Linq.Expressions;
using Microsoft.EntityFrameworkCore.Query.NavigationExpansion;
Expand Down Expand Up @@ -71,8 +70,7 @@ public Expression Inject(Expression expression)
}

private LambdaExpression ConvertToLambda(Expression result, ParameterExpression resultParameter)
{
return _indexMapParameter != null
=> _indexMapParameter != null
? Expression.Lambda(
result,
QueryCompilationContext.QueryContextParameter,
Expand All @@ -86,7 +84,6 @@ private LambdaExpression ConvertToLambda(Expression result, ParameterExpression
_dataReaderParameter,
resultParameter,
_resultCoordinatorParameter);
}

protected override Expression VisitExtension(Expression extensionExpression)
{
Expand Down Expand Up @@ -186,10 +183,8 @@ protected override Expression VisitExtension(Expression extensionExpression)
}

private Expression GenerateKey(ProjectionBindingExpression projectionBindingExpression)
{
return projectionBindingExpression.ProjectionMember != null
=> projectionBindingExpression.ProjectionMember != null
? _selectExpression.GetMappedProjection(projectionBindingExpression.ProjectionMember)
: projectionBindingExpression;
}
}
}
2 changes: 1 addition & 1 deletion src/EFCore/Query/NavigationExpansion/IncludeHelpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ public static class IncludeHelpers
{
public static void CopyIncludeInformation(NavigationTreeNode originalNavigationTree, NavigationTreeNode newNavigationTree, SourceMapping newSourceMapping)
{
foreach (var child in originalNavigationTree.Children.Where(n => n.Included == NavigationTreeNodeIncludeMode.ReferencePending || n.Included == NavigationTreeNodeIncludeMode.Collection))
foreach (var child in originalNavigationTree.Children.Where(n => n.IncludeState == NavigationState.ReferencePending || n.IncludeState == NavigationState.CollectionPending))
{
var copy = NavigationTreeNode.Create(newSourceMapping, child.Navigation, newNavigationTree, true);
CopyIncludeInformation(child, copy, newSourceMapping);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,5 @@ protected override Expression VisitChildren(ExpressionVisitor visitor)
? new MaterializeCollectionNavigationExpression(subquery, Navigation)
: this;
}


}
}
31 changes: 0 additions & 31 deletions src/EFCore/Query/NavigationExpansion/NavigationExpander.cs

This file was deleted.

Loading