Esempio n. 1
0
        /// <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);
        }
Esempio n. 4
0
            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));
            }