Пример #1
0
        /// <summary>
        ///     Constructs a new ObjectSpanRewriter that will attempt to apply spanning to the specified query
        ///     (represented as a DbExpression) when <see cref="RewriteQuery" /> is called.
        /// </summary>
        /// <param name="toRewrite"> A <see cref="DbExpression" /> representing the query to span. </param>
        internal ObjectSpanRewriter(DbCommandTree tree, DbExpression toRewrite, AliasGenerator aliasGenerator)
        {
            Debug.Assert(toRewrite != null, "Expression to rewrite cannot be null");

            _toRewrite = toRewrite;
            _tree = tree;
            _aliasGenerator = aliasGenerator;
        }
        /// <summary>
        ///     Constructs a new ObjectSpanRewriter that will attempt to apply spanning to the specified query
        ///     (represented as a DbExpression) when <see cref="RewriteQuery" /> is called.
        /// </summary>
        /// <param name="toRewrite">
        ///     A <see cref="DbExpression" /> representing the query to span.
        /// </param>
        internal ObjectSpanRewriter(DbCommandTree tree, DbExpression toRewrite, AliasGenerator aliasGenerator)
        {
            DebugCheck.NotNull(toRewrite);

            _toRewrite = toRewrite;
            _tree = tree;
            _aliasGenerator = aliasGenerator;
        }
        public virtual ObjectQueryExecutionPlan Prepare(
            ObjectContext context, DbQueryCommandTree tree, Type elementType, MergeOption mergeOption, bool streaming, Span span,
            IEnumerable<Tuple<ObjectParameter, QueryParameterExpression>> compiledQueryParameters, AliasGenerator aliasGenerator)
        {
            var treeResultType = tree.Query.ResultType;

            // Rewrite this tree for Span?
            DbExpression spannedQuery;
            SpanIndex spanInfo;
            if (ObjectSpanRewriter.TryRewrite(tree, span, mergeOption, aliasGenerator, out spannedQuery, out spanInfo))
            {
                tree = DbQueryCommandTree.FromValidExpression(
                    tree.MetadataWorkspace, tree.DataSpace, spannedQuery, tree.UseDatabaseNullSemantics);
            }
            else
            {
                spanInfo = null;
            }

            var entityDefinition = CreateCommandDefinition(context, tree);

            var shaperFactory = Translator.TranslateColumnMap(
                _translator, elementType, entityDefinition.CreateColumnMap(null),
                context.MetadataWorkspace, spanInfo, mergeOption, streaming, false);

            // attempt to determine entity information for this query (e.g. which entity type and which entity set)

            EntitySet singleEntitySet = null;

            // determine if the entity set is unambiguous given the entity type
            if (treeResultType.EdmType.BuiltInTypeKind == BuiltInTypeKind.CollectionType
                && entityDefinition.EntitySets != null)
            {
                foreach (var entitySet in entityDefinition.EntitySets)
                {
                    if (entitySet != null
                        && entitySet.ElementType.IsAssignableFrom(((CollectionType)treeResultType.EdmType).TypeUsage.EdmType))
                    {
                        if (singleEntitySet == null)
                        {
                            // found a single match
                            singleEntitySet = entitySet;
                        }
                        else
                        {
                            // there's more than one matching entity set
                            singleEntitySet = null;
                            break;
                        }
                    }
                }
            }

            return new ObjectQueryExecutionPlan(
                entityDefinition, shaperFactory, treeResultType, mergeOption, streaming, singleEntitySet, compiledQueryParameters);
        }
Пример #4
0
        internal static bool TryRewrite(
            DbQueryCommandTree tree, Span span, MergeOption mergeOption, AliasGenerator aliasGenerator, out DbExpression newQuery,
            out SpanIndex spanInfo)
        {
            newQuery = null;
            spanInfo = null;

            ObjectSpanRewriter rewriter = null;
            var requiresRelationshipSpan = Span.RequiresRelationshipSpan(mergeOption);

            // Potentially perform a rewrite for span.
            // Note that the public 'Span' property is NOT used to retrieve the Span instance
            // since this forces creation of a Span object that may not be required.
            if (span != null
                && span.SpanList.Count > 0)
            {
                rewriter = new ObjectFullSpanRewriter(tree, tree.Query, span, aliasGenerator);
            }
            else if (requiresRelationshipSpan)
            {
                rewriter = new ObjectSpanRewriter(tree, tree.Query, aliasGenerator);
            }

            if (rewriter != null)
            {
                rewriter.RelationshipSpan = requiresRelationshipSpan;
                newQuery = rewriter.RewriteQuery();
                if (newQuery != null)
                {
                    Debug.Assert(
                        rewriter.SpanIndex != null || tree.Query.ResultType.EdmEquals(newQuery.ResultType),
                        "Query was rewritten for Span but no SpanIndex was created?");
                    spanInfo = rewriter.SpanIndex;
                }
            }

            return (spanInfo != null);
        }
        internal ObjectFullSpanRewriter(DbCommandTree tree, DbExpression toRewrite, Span span, AliasGenerator aliasGenerator)
            : base(tree, toRewrite, aliasGenerator)
        {
            Debug.Assert(span != null, "Span cannot be null");
            Debug.Assert(span.SpanList.Count > 0, "At least one span path is required");

            // Retrieve the effective 'T' of the ObjectQuery<T> that produced
            // the Command Tree that is being rewritten. This could be either
            // literally 'T' or Collection<T>.
            EntityType entityType = null;
            if (!TryGetEntityType(Query.ResultType, out entityType))
            {
                // If the result type of the query is neither an Entity type nor a collection
                // type with an Entity element type, then full Span is currently not allowed.
                throw new InvalidOperationException(Strings.ObjectQuery_Span_IncludeRequiresEntityOrEntityCollection);
            }

            // Construct the SpanPathInfo navigation property tree using the
            // list of Include Span paths from the Span object:
            // Create a SpanPathInfo instance that represents the root of the tree
            // and takes its Entity type from the Entity type of the result type of the query.
            var spanRoot = new SpanPathInfo(entityType);

            // Populate the tree of navigation properties based on the navigation property names
            // in the Span paths from the Span object. Commonly rooted span paths are merged, so
            // that paths of "Customer.Order" and "Customer.Address", for example, will share a
            // common SpanPathInfo for "Customer" in the Children collection of the root SpanPathInfo,
            // and that SpanPathInfo will contain one child for "Order" and another for "Address".
            foreach (var path in span.SpanList)
            {
                AddSpanPath(spanRoot, path.Navigations);
            }

            // The 'current' span path is initialized to the root of the Include span tree
            _currentSpanPath.Push(spanRoot);
        }
Пример #6
0
 internal OrderByLifter(AliasGenerator aliasGenerator)
 {
     _aliasGenerator = aliasGenerator;
 }
Пример #7
0
 internal SortLifter(DbSortExpression sort, AliasGenerator aliasGenerator)
     : base(sort, aliasGenerator)
 {
     _sort = sort;
     _source = sort.Input.Expression;
 }
Пример #8
0
            internal static DbExpression FindNavigationExpression(
                DbExpression expression, AliasGenerator aliasGenerator, out NavigationInfo navInfo)
            {
                Debug.Assert(TypeSemantics.IsCollectionType(expression.ResultType), "Non-collection input to projection?");

                navInfo = null;

                var elementType = ((CollectionType)expression.ResultType.EdmType).TypeUsage;
                if (!TypeSemantics.IsEntityType(elementType)
                    && !TypeSemantics.IsReferenceType(elementType))
                {
                    return expression;
                }

                var visitor = new RelationshipNavigationVisitor(aliasGenerator);
                var rewrittenExpression = visitor.Find(expression);
                if (!ReferenceEquals(expression, rewrittenExpression))
                {
                    Debug.Assert(
                        visitor._original != null && visitor._rewritten != null, "Expression was rewritten but no navigation was found?");
                    navInfo = new NavigationInfo(visitor._original, visitor._rewritten);
                    return rewrittenExpression;
                }
                else
                {
                    return expression;
                }
            }
Пример #9
0
 private RelationshipNavigationVisitor(AliasGenerator aliasGenerator)
 {
     _aliasGenerator = aliasGenerator;
 }
Пример #10
0
 // <summary>
 // Returns a lifter instance which supports lifting the intrinsic order of the given
 // source expression across specific operations (filter, project, oftype, skip, and limit)
 // </summary>
 // <remarks>
 // Lifting only occurs for expressions that are ordered. Each of the nested
 // OrderByLifterBase class implementations represents one or two of the ordered patterns with
 // the exception of the PassthroughOrderByLifter. The latter class represents expressions
 // without intrinsic order that therefore require no lifting.
 // </remarks>
 internal static OrderByLifterBase GetLifter(DbExpression source, AliasGenerator aliasGenerator)
 {
     if (source.ExpressionKind
         == DbExpressionKind.Sort)
     {
         return new SortLifter((DbSortExpression)source, aliasGenerator);
     }
     if (source.ExpressionKind
         == DbExpressionKind.Project)
     {
         var project = (DbProjectExpression)source;
         var projectInput = project.Input.Expression;
         if (projectInput.ExpressionKind
             == DbExpressionKind.Sort)
         {
             return new ProjectSortLifter(project, (DbSortExpression)projectInput, aliasGenerator);
         }
         if (projectInput.ExpressionKind
             == DbExpressionKind.Skip)
         {
             return new ProjectSkipLifter(project, (DbSkipExpression)projectInput, aliasGenerator);
         }
         if (projectInput.ExpressionKind
             == DbExpressionKind.Limit)
         {
             var limit = (DbLimitExpression)projectInput;
             var limitInput = limit.Argument;
             if (limitInput.ExpressionKind
                 == DbExpressionKind.Sort)
             {
                 return new ProjectLimitSortLifter(project, limit, (DbSortExpression)limitInput, aliasGenerator);
             }
             if (limitInput.ExpressionKind
                 == DbExpressionKind.Skip)
             {
                 return new ProjectLimitSkipLifter(project, limit, (DbSkipExpression)limitInput, aliasGenerator);
             }
         }
     }
     if (source.ExpressionKind
         == DbExpressionKind.Skip)
     {
         return new SkipLifter((DbSkipExpression)source, aliasGenerator);
     }
     if (source.ExpressionKind
         == DbExpressionKind.Limit)
     {
         var limit = (DbLimitExpression)source;
         var limitInput = limit.Argument;
         if (limitInput.ExpressionKind
             == DbExpressionKind.Sort)
         {
             return new LimitSortLifter(limit, (DbSortExpression)limitInput, aliasGenerator);
         }
         if (limitInput.ExpressionKind
             == DbExpressionKind.Skip)
         {
             return new LimitSkipLifter(limit, (DbSkipExpression)limitInput, aliasGenerator);
         }
         if (limitInput.ExpressionKind
             == DbExpressionKind.Project)
         {
             var project = (DbProjectExpression)limitInput;
             var projectInput = project.Input.Expression;
             if (projectInput.ExpressionKind
                 == DbExpressionKind.Sort)
             {
                 // source.Sort(o).Project(p).Limit(k).* is equivalent to transformation for 
                 // source.Sort(o).Limit(k).Project(p).* 
                 return new ProjectLimitSortLifter(project, limit, (DbSortExpression)projectInput, aliasGenerator);
             }
             if (projectInput.ExpressionKind
                 == DbExpressionKind.Skip)
             {
                 // source.Skip(k, o).Project(p).Limit(k2).* is equivalent to transformation for 
                 // source.Skip(k, o).Limit(k2).Project(p).*
                 return new ProjectLimitSkipLifter(project, limit, (DbSkipExpression)projectInput, aliasGenerator);
             }
         }
     }
     return new PassthroughOrderByLifter(source, aliasGenerator);
 }
Пример #11
0
 internal LimitSkipLifter(DbLimitExpression limit, DbSkipExpression skip, AliasGenerator aliasGenerator)
     : base(limit, aliasGenerator)
 {
     _limit = limit;
     _skip = skip;
 }
Пример #12
0
 protected OrderByLifterBase(DbExpression root, AliasGenerator aliasGenerator)
 {
     _root = root;
     _aliasGenerator = aliasGenerator;
 }
Пример #13
0
 internal PassthroughOrderByLifter(DbExpression source, AliasGenerator aliasGenerator)
     : base(source, aliasGenerator)
 {
 }
Пример #14
0
 internal LimitSortLifter(DbLimitExpression limit, DbSortExpression sort, AliasGenerator aliasGenerator)
     : base(limit, aliasGenerator)
 {
     _limit = limit;
     _sort = sort;
 }
Пример #15
0
 internal ProjectSortLifter(DbProjectExpression project, DbSortExpression sort, AliasGenerator aliasGenerator)
     : base(project, aliasGenerator)
 {
     _project = project;
     _sort = sort;
     _source = sort.Input.Expression;
 }
Пример #16
0
 internal SkipLifter(DbSkipExpression skip, AliasGenerator aliasGenerator)
     : base(skip, aliasGenerator)
 {
     _skip = skip;
     _source = skip.Input.Expression;
 }
Пример #17
0
 internal ProjectSkipLifter(DbProjectExpression project, DbSkipExpression skip, AliasGenerator aliasGenerator)
     : base(project, aliasGenerator)
 {
     _project = project;
     _skip = skip;
     _source = _skip.Input.Expression;
 }
Пример #18
0
 internal ProjectLimitSortLifter(
     DbProjectExpression project, DbLimitExpression limit, DbSortExpression sort, AliasGenerator aliasGenerator)
     : base(project, aliasGenerator)
 {
     _project = project;
     _limit = limit;
     _sort = sort;
 }