/// <summary> /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to /// the same compatibility standards as public APIs. It may be changed or removed without notice in /// any release. You should only use it directly in your code with extreme caution and knowing that /// doing so can result in application failures when updating to a new Entity Framework Core release. /// </summary> protected override Expression VisitExtension(Expression extensionExpression) { Check.NotNull(extensionExpression, nameof(extensionExpression)); switch (extensionExpression) { case EntityShaperExpression entityShaperExpression: { var projectionBindingExpression = (ProjectionBindingExpression)entityShaperExpression.ValueBufferExpression; VerifySelectExpression(projectionBindingExpression); if (_clientEval) { var entityProjection = (EntityProjectionExpression)_selectExpression.GetMappedProjection( projectionBindingExpression.ProjectionMember); return(entityShaperExpression.Update( new ProjectionBindingExpression( _selectExpression, _selectExpression.AddToProjection(entityProjection), typeof(ValueBuffer)))); } _projectionMapping[_projectionMembers.Peek()] = _selectExpression.GetMappedProjection(projectionBindingExpression.ProjectionMember); return(entityShaperExpression.Update( new ProjectionBindingExpression(_selectExpression, _projectionMembers.Peek(), typeof(ValueBuffer)))); } case MaterializeCollectionNavigationExpression materializeCollectionNavigationExpression: return(materializeCollectionNavigationExpression.Navigation is INavigation embeddableNavigation && embeddableNavigation.IsEmbedded() ? base.Visit(materializeCollectionNavigationExpression.Subquery) : base.VisitExtension(materializeCollectionNavigationExpression)); case IncludeExpression includeExpression: if (!_clientEval) { return(null); } if (!(includeExpression.Navigation is INavigation includableNavigation && includableNavigation.IsEmbedded())) { throw new InvalidOperationException( CosmosStrings.NonEmbeddedIncludeNotSupported(includeExpression.Navigation)); } _includedNavigations.Push(includableNavigation); var newIncludeExpression = base.VisitExtension(includeExpression); _includedNavigations.Pop(); return(newIncludeExpression); default: throw new InvalidOperationException(CoreStrings.TranslationFailed(extensionExpression.Print())); } }
protected override Expression VisitMethodCall(MethodCallExpression methodCallExpression) { Check.NotNull(methodCallExpression, nameof(methodCallExpression)); var method = methodCallExpression.Method; var genericMethod = method.IsGenericMethod ? method.GetGenericMethodDefinition() : null; if (genericMethod == EntityFrameworkCore.Infrastructure.ExpressionExtensions.ValueBufferTryReadValueMethod) { var property = methodCallExpression.Arguments[2].GetConstantValue <IProperty>(); Expression innerExpression; if (methodCallExpression.Arguments[0] is ProjectionBindingExpression projectionBindingExpression) { var projection = GetProjection(projectionBindingExpression); innerExpression = Expression.Convert( CreateReadJTokenExpression(_jObjectParameter, projection.Alias), typeof(JObject)); } else { innerExpression = _materializationContextBindings[ (ParameterExpression)((MethodCallExpression)methodCallExpression.Arguments[0]).Object]; } return(CreateGetValueExpression(innerExpression, property, methodCallExpression.Type)); } if (method.DeclaringType == typeof(Enumerable) && method.Name == nameof(Enumerable.Select) && genericMethod == EnumerableMethods.Select) { var lambda = (LambdaExpression)methodCallExpression.Arguments[1]; if (lambda.Body is IncludeExpression includeExpression) { if (!(includeExpression.Navigation is INavigation navigation) || navigation.IsOnDependent || navigation.ForeignKey.DeclaringEntityType.IsDocumentRoot()) { throw new InvalidOperationException( CosmosStrings.NonEmbeddedIncludeNotSupported(includeExpression.Navigation)); } _pendingIncludes.Add(includeExpression); Visit(includeExpression.EntityExpression); // Includes on collections are processed when visiting CollectionShaperExpression return(Visit(methodCallExpression.Arguments[0])); } } return(base.VisitMethodCall(methodCallExpression)); }
protected override Expression VisitExtension(Expression extensionExpression) { Check.NotNull(extensionExpression, nameof(extensionExpression)); switch (extensionExpression) { case ProjectionBindingExpression projectionBindingExpression: { var projection = GetProjection(projectionBindingExpression); return(CreateGetValueExpression( _jObjectParameter, projection.Alias, projectionBindingExpression.Type, (projection.Expression as SqlExpression)?.TypeMapping)); } case CollectionShaperExpression collectionShaperExpression: { ObjectArrayProjectionExpression objectArrayProjection; switch (collectionShaperExpression.Projection) { case ProjectionBindingExpression projectionBindingExpression: var projection = GetProjection(projectionBindingExpression); objectArrayProjection = (ObjectArrayProjectionExpression)projection.Expression; break; case ObjectArrayProjectionExpression objectArrayProjectionExpression: objectArrayProjection = objectArrayProjectionExpression; break; default: throw new InvalidOperationException(CoreStrings.TranslationFailed(extensionExpression.Print())); } var jArray = _projectionBindings[objectArrayProjection]; var jObjectParameter = Expression.Parameter(typeof(JObject), jArray.Name + "Object"); var ordinalParameter = Expression.Parameter(typeof(int), jArray.Name + "Ordinal"); var accessExpression = objectArrayProjection.InnerProjection.AccessExpression; _projectionBindings[accessExpression] = jObjectParameter; _ownerMappings[accessExpression] = (objectArrayProjection.Navigation.DeclaringEntityType, objectArrayProjection.AccessExpression); _ordinalParameterBindings[accessExpression] = Expression.Add( ordinalParameter, Expression.Constant(1, typeof(int))); var innerShaper = (BlockExpression)Visit(collectionShaperExpression.InnerShaper); innerShaper = AddIncludes(innerShaper); var entities = Expression.Call( EnumerableMethods.SelectWithOrdinal.MakeGenericMethod(typeof(JObject), innerShaper.Type), Expression.Call( EnumerableMethods.Cast.MakeGenericMethod(typeof(JObject)), jArray), Expression.Lambda(innerShaper, jObjectParameter, ordinalParameter)); var navigation = collectionShaperExpression.Navigation; return(Expression.Call( _populateCollectionMethodInfo.MakeGenericMethod(navigation.TargetEntityType.ClrType, navigation.ClrType), Expression.Constant(navigation.GetCollectionAccessor()), entities)); } case IncludeExpression includeExpression: { if (!(includeExpression.Navigation is INavigation navigation) || navigation.IsOnDependent || navigation.ForeignKey.DeclaringEntityType.IsDocumentRoot()) { throw new InvalidOperationException( CosmosStrings.NonEmbeddedIncludeNotSupported(includeExpression.Navigation)); } var isFirstInclude = _pendingIncludes.Count == 0; _pendingIncludes.Add(includeExpression); var jObjectBlock = Visit(includeExpression.EntityExpression) as BlockExpression; if (!isFirstInclude) { return(jObjectBlock); } Check.DebugAssert(jObjectBlock != null, "The first include must end up on a valid shaper block"); // These are the expressions added by JObjectInjectingExpressionVisitor var jObjectCondition = (ConditionalExpression)jObjectBlock.Expressions[^ 1];