Skip to content

Commit

Permalink
Add support for eager loaded navigations
Browse files Browse the repository at this point in the history
  • Loading branch information
AndriySvyryd committed Jul 8, 2019
1 parent ed27c18 commit 1cf9a3b
Show file tree
Hide file tree
Showing 22 changed files with 593 additions and 559 deletions.
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,82 @@ 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;
case NavigationBindingExpression navigationBindingExpression:
return navigationBindingExpression;
}

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
31 changes: 0 additions & 31 deletions src/EFCore/Query/NavigationExpansion/NavigationExpander.cs

This file was deleted.

Loading

0 comments on commit 1cf9a3b

Please sign in to comment.