/// <summary> /// This API supports the Entity Framework Core infrastructure and is not intended to be used /// directly from your code. This API may change or be removed in future releases. /// </summary> public override void VisitAdditionalFromClause( AdditionalFromClause fromClause, QueryModel queryModel, int index) { if (fromClause.FromExpression is SubQueryExpression subQueryExpression && subQueryExpression.QueryModel.MainFromClause.FromExpression is QuerySourceReferenceExpression qsre && subQueryExpression.QueryModel.SelectClause.Selector is QuerySourceReferenceExpression && qsre.ReferencedQuerySource is GroupJoinClause groupJoinClause && !(groupJoinClause.JoinClause.InnerSequence is SubQueryExpression) && queryModel.CountQuerySourceReferences(groupJoinClause) == 1 && subQueryExpression.QueryModel.BodyClauses.Any() && subQueryExpression.QueryModel.BodyClauses.All(c => c is WhereClause)) { var newMainFromClause = new MainFromClause( groupJoinClause.JoinClause.ItemName, groupJoinClause.JoinClause.ItemType, groupJoinClause.JoinClause.InnerSequence); var newSelectClause = new SelectClause( new QuerySourceReferenceExpression(newMainFromClause)); var newSubQueryModel = new QueryModel(newMainFromClause, newSelectClause); ShiftBodyClauses(subQueryExpression.QueryModel, newSubQueryModel); var entityType = _queryCompilationContext.FindEntityType(subQueryExpression.QueryModel.MainFromClause); if (entityType != null) { _queryCompilationContext.AddOrUpdateMapping(newMainFromClause, entityType); } var newSubQueryExpression = new SubQueryExpression(newSubQueryModel); groupJoinClause.JoinClause.InnerSequence = newSubQueryExpression; if (!subQueryExpression.QueryModel.ResultOperators.Any()) { fromClause.FromExpression = qsre; } } }
private void UpdateCurrentParameter(IQuerySource querySource, Type type) { CurrentParameter = Expression.Parameter(type, querySource.ItemName); QueryCompilationContext.AddOrUpdateMapping(querySource, CurrentParameter); }
/// <summary> /// This API supports the Entity Framework Core infrastructure and is not intended to be used /// directly from your code. This API may change or be removed in future releases. /// </summary> public override void VisitResultOperator(ResultOperatorBase resultOperator, QueryModel queryModel, int index) { if (resultOperator is ValueFromSequenceResultOperatorBase && !(resultOperator is FirstResultOperator) && !(resultOperator is SingleResultOperator) && !(resultOperator is LastResultOperator) && !queryModel.ResultOperators .Any(r => r is TakeResultOperator || r is SkipResultOperator)) { for (var i = queryModel.BodyClauses.Count - 1; i >= 0; i--) { if (queryModel.BodyClauses[i] is OrderByClause) { queryModel.BodyClauses.RemoveAt(i); } } } if (resultOperator is OfTypeResultOperator ofTypeOperator) { var searchedItemType = ofTypeOperator.SearchedItemType; if (searchedItemType == queryModel.MainFromClause.ItemType) { queryModel.ResultOperators.RemoveAt(index); } else { var entityType = _queryCompilationContext.Model.FindEntityType(searchedItemType) ?? _queryCompilationContext.FindEntityType(queryModel.MainFromClause); if (entityType != null) { var oldQuerySource = queryModel.MainFromClause; if (((oldQuerySource.FromExpression as ConstantExpression)?.Value as IQueryable)?.Provider is IAsyncQueryProvider entityQueryProvider) { queryModel.ResultOperators.RemoveAt(index); var newMainFromClause = new MainFromClause( oldQuerySource.ItemName, entityType.ClrType, entityQueryProvider.CreateEntityQueryableExpression(entityType.ClrType)); queryModel.MainFromClause = newMainFromClause; _queryCompilationContext.AddOrUpdateMapping(newMainFromClause, entityType); UpdateQuerySourceMapping( queryModel, oldQuerySource, new QuerySourceReferenceExpression(newMainFromClause)); } } } } ProcessSetResultOperator(resultOperator); TryOptimizeContains(resultOperator, queryModel); base.VisitResultOperator(resultOperator, queryModel, index); }
private void Rewrite(QueryModel collectionQueryModel, INavigation navigation) { var querySourceReferenceFindingExpressionTreeVisitor = new QuerySourceReferenceFindingExpressionVisitor(); var whereClause = collectionQueryModel.BodyClauses .OfType <WhereClause>() .SingleOrDefault(); if (whereClause == null) { // Assuming this is a client query collectionQueryModel.MainFromClause.FromExpression = Expression.Coalesce( collectionQueryModel.MainFromClause.FromExpression, Expression.Call(null, _emptyMethodInfo.MakeGenericMethod(navigation.GetTargetType().ClrType))); return; } whereClause.TransformExpressions(querySourceReferenceFindingExpressionTreeVisitor.Visit); collectionQueryModel.BodyClauses.Remove(whereClause); var parentQuerySourceReferenceExpression = querySourceReferenceFindingExpressionTreeVisitor.QuerySourceReferenceExpression; var parentQuerySource = parentQuerySourceReferenceExpression.ReferencedQuerySource; BuildParentOrderings( _parentQueryModel, navigation, parentQuerySourceReferenceExpression, ParentOrderings); var querySourceMapping = new QuerySourceMapping(); var clonedParentQueryModel = _parentQueryModel.Clone(querySourceMapping); _queryCompilationContext.UpdateMapping(querySourceMapping); _queryCompilationContext.CloneAnnotations(querySourceMapping, clonedParentQueryModel); var clonedParentQuerySourceReferenceExpression = (QuerySourceReferenceExpression)querySourceMapping.GetExpression(parentQuerySource); var clonedParentQuerySource = clonedParentQuerySourceReferenceExpression.ReferencedQuerySource; AdjustPredicate( clonedParentQueryModel, clonedParentQuerySource, clonedParentQuerySourceReferenceExpression); clonedParentQueryModel.SelectClause = new SelectClause(Expression.Default(typeof(AnonymousObject))); var subQueryProjection = new List <Expression>(); var lastResultOperator = ProcessResultOperators(clonedParentQueryModel); clonedParentQueryModel.ResultTypeOverride = typeof(IQueryable <>).MakeGenericType(clonedParentQueryModel.SelectClause.Selector.Type); var parentItemName = parentQuerySource.HasGeneratedItemName() ? navigation.DeclaringEntityType.ShortName()[0].ToString().ToLowerInvariant() : parentQuerySource.ItemName; collectionQueryModel.MainFromClause.ItemName = $"{parentItemName}.{navigation.Name}"; var collectionQuerySourceReferenceExpression = new QuerySourceReferenceExpression(collectionQueryModel.MainFromClause); _queryCompilationContext.AddOrUpdateMapping(collectionQueryModel.MainFromClause, navigation.GetTargetType()); var joinQuerySourceReferenceExpression = CreateJoinToParentQuery( clonedParentQueryModel, clonedParentQuerySourceReferenceExpression, collectionQuerySourceReferenceExpression, navigation.ForeignKey, collectionQueryModel, subQueryProjection); ApplyParentOrderings( ParentOrderings, clonedParentQueryModel, querySourceMapping, lastResultOperator); LiftOrderBy( clonedParentQuerySource, joinQuerySourceReferenceExpression, clonedParentQueryModel, collectionQueryModel, subQueryProjection); clonedParentQueryModel.SelectClause.Selector = Expression.New( AnonymousObject.AnonymousObjectCtor, Expression.NewArrayInit( typeof(object), subQueryProjection)); }