Пример #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>
        protected override void FlattenSubQuery(
            [NotNull] SubQueryExpression subQueryExpression,
            [NotNull] IFromClause fromClause,
            [NotNull] QueryModel queryModel,
            int destinationIndex)
        {
            var subQueryModel = subQueryExpression.QueryModel;

            VisitQueryModel(subQueryModel);

            if (subQueryModel.ResultOperators
                .All(ro => ro is CastResultOperator) &&
                !subQueryModel.BodyClauses.Any(bc => bc is OrderByClause) ||
                queryModel.IsIdentityQuery() &&
                !queryModel.ResultOperators.Any())
            {
                string itemName;

                var innerMainFromClause  = subQueryExpression.QueryModel.MainFromClause;
                var isGeneratedNameOuter = fromClause.HasGeneratedItemName();

                if (innerMainFromClause.HasGeneratedItemName() &&
                    !isGeneratedNameOuter)
                {
                    itemName = fromClause.ItemName;
                }
                else
                {
                    itemName = innerMainFromClause.ItemName;
                }

                var fromClauseData
                    = new FromClauseData(
                          itemName, innerMainFromClause.ItemType, innerMainFromClause.FromExpression);

                fromClause.CopyFromSource(fromClauseData);

                UpdateQuerySourceMapping(
                    queryModel,
                    fromClause,
                    subQueryExpression.QueryModel.SelectClause.Selector);

                InsertBodyClauses(subQueryExpression.QueryModel.BodyClauses, queryModel, destinationIndex);

                foreach (var resultOperator in subQueryModel.ResultOperators.Reverse())
                {
                    queryModel.ResultOperators.Insert(0, resultOperator);
                }

                UpdateQuerySourceMapping(
                    queryModel,
                    innerMainFromClause,
                    new QuerySourceReferenceExpression(fromClause));
            }
        }
Пример #2
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>
        protected override void FlattenSubQuery(
            SubQueryExpression subQueryExpression,
            IFromClause fromClause,
            QueryModel queryModel,
            int destinationIndex)
        {
            var subQueryModel = subQueryExpression.QueryModel;

            VisitQueryModel(subQueryModel);

            // no groupby and no distinct
            var emptyQueryModelWithFlattenableResultOperatorInSubquery
                = !queryModel.BodyClauses.Any() &&
                  subQueryModel.ResultOperators.All(
                      ro => ro is CastResultOperator ||
                      ro is DefaultIfEmptyResultOperator ||
                      ro is ExceptResultOperator ||
                      ro is OfTypeResultOperator ||
                      ro is ReverseResultOperator ||
                      ro is SkipResultOperator ||
                      ro is TakeResultOperator);

            // we can lift distinct however if the outer query has result operator that doesn't care about having correct element count
            var emptyQueryModelWithResultOperatorThatIgnoresElementCountAndDistinctInSubquery
                = !queryModel.BodyClauses.Any() &&
                  subQueryModel.ResultOperators.Any(ro => ro is DistinctResultOperator) &&
                  queryModel.ResultOperators.Any(
                      ro => ro is ContainsResultOperator ||
                      ro is AnyResultOperator ||
                      ro is AllResultOperator ||
                      ro is MinResultOperator ||
                      ro is MaxResultOperator);

            var subqueryInMainClauseWithoutResultOperatorsProjectingItsMainClause
                = fromClause is MainFromClause &&
                  !subQueryModel.ResultOperators.Any() &&
                  subQueryModel.SelectClause.Selector is QuerySourceReferenceExpression subquerySelectorsQsre &&
                  subquerySelectorsQsre.ReferencedQuerySource == subQueryModel.MainFromClause;

            if (subQueryModel.ResultOperators.All(ro => ro is CastResultOperator) &&
                !subQueryModel.BodyClauses.Any(bc => bc is OrderByClause) &&
                subQueryModel.SelectClause.Selector.NodeType != ExpressionType.MemberInit &&
                subQueryModel.SelectClause.Selector.NodeType != ExpressionType.New ||
                queryModel.IsIdentityQuery() &&
                !queryModel.ResultOperators.Any() ||
                emptyQueryModelWithFlattenableResultOperatorInSubquery ||
                emptyQueryModelWithResultOperatorThatIgnoresElementCountAndDistinctInSubquery ||
                subqueryInMainClauseWithoutResultOperatorsProjectingItsMainClause)
            {
                string itemName;

                var querySourceMapping  = new QuerySourceMapping();
                var clonedSubQueryModel = subQueryModel.Clone(querySourceMapping);
                UpdateQueryAnnotations(subQueryModel, querySourceMapping);

                var innerMainFromClause  = clonedSubQueryModel.MainFromClause;
                var isGeneratedNameOuter = fromClause.HasGeneratedItemName();

                if (innerMainFromClause.HasGeneratedItemName() &&
                    !isGeneratedNameOuter)
                {
                    itemName = fromClause.ItemName;
                }
                else
                {
                    itemName = innerMainFromClause.ItemName;
                }

                var fromClauseData
                    = new FromClauseData(
                          itemName, innerMainFromClause.ItemType, innerMainFromClause.FromExpression);

                fromClause.CopyFromSource(fromClauseData);

                var newExpression           = clonedSubQueryModel.SelectClause.Selector;
                var newExpressionTypeInfo   = newExpression.Type.GetTypeInfo();
                var castResultOperatorTypes = clonedSubQueryModel.ResultOperators.OfType <CastResultOperator>().Select(cre => cre.CastItemType).ToList();
                var type = castResultOperatorTypes.LastOrDefault(t => newExpressionTypeInfo.IsAssignableFrom(t.GetTypeInfo()));

                if (type != null &&
                    type != newExpression.Type)
                {
                    newExpression = Expression.Convert(newExpression, type);
                }

                UpdateQuerySourceMapping(
                    queryModel,
                    fromClause,
                    newExpression);

                InsertBodyClauses(clonedSubQueryModel.BodyClauses, queryModel, destinationIndex);

                foreach (var resultOperator in clonedSubQueryModel.ResultOperators.Where(ro => !(ro is CastResultOperator)).Reverse())
                {
                    queryModel.ResultOperators.Insert(0, resultOperator);
                }

                UpdateQuerySourceMapping(
                    queryModel,
                    innerMainFromClause,
                    new QuerySourceReferenceExpression(fromClause));
            }
        }
Пример #3
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>
        protected override void FlattenSubQuery(
            [NotNull] SubQueryExpression subQueryExpression,
            [NotNull] IFromClause fromClause,
            [NotNull] QueryModel queryModel,
            int destinationIndex)
        {
            var subQueryModel = subQueryExpression.QueryModel;

            VisitQueryModel(subQueryModel);

            if ((subQueryModel.ResultOperators
                 .All(ro => ro is CastResultOperator) &&
                 !subQueryModel.BodyClauses.Any(bc => bc is OrderByClause)) ||
                (queryModel.IsIdentityQuery() &&
                 !queryModel.ResultOperators.Any()))
            {
                string itemName;

                var innerMainFromClause  = subQueryExpression.QueryModel.MainFromClause;
                var isGeneratedNameOuter = fromClause.HasGeneratedItemName();

                if (innerMainFromClause.HasGeneratedItemName() &&
                    !isGeneratedNameOuter)
                {
                    itemName = fromClause.ItemName;
                }
                else
                {
                    itemName = innerMainFromClause.ItemName;
                }

                var fromClauseData
                    = new FromClauseData(
                          itemName, innerMainFromClause.ItemType, innerMainFromClause.FromExpression);

                fromClause.CopyFromSource(fromClauseData);

                var innerSelectorMapping = new QuerySourceMapping();

                innerSelectorMapping.AddMapping(fromClause, subQueryExpression.QueryModel.SelectClause.Selector);

                queryModel.TransformExpressions(
                    ex => ReferenceReplacingExpressionVisitor
                    .ReplaceClauseReferences(ex, innerSelectorMapping, false));

                InsertBodyClauses(subQueryExpression.QueryModel.BodyClauses, queryModel, destinationIndex);

                foreach (var resultOperator in subQueryModel.ResultOperators.Reverse())
                {
                    queryModel.ResultOperators.Insert(0, resultOperator);
                }

                var innerBodyClauseMapping = new QuerySourceMapping();

                innerBodyClauseMapping
                .AddMapping(innerMainFromClause, new QuerySourceReferenceExpression(fromClause));

                queryModel.TransformExpressions(
                    ex => ReferenceReplacingExpressionVisitor
                    .ReplaceClauseReferences(ex, innerBodyClauseMapping, false));

                foreach (var queryAnnotation
                         in _queryAnnotations
                         .Where(qa => qa.QuerySource == subQueryExpression.QueryModel.MainFromClause))
                {
                    queryAnnotation.QuerySource = fromClause;
                    queryAnnotation.QueryModel  = queryModel;
                }
            }
        }