예제 #1
0
        internal override SpanTrackingInfo CreateEntitySpanTrackingInfo(DbExpression expression, EntityType entityType)
        {
            SpanTrackingInfo tracking = new SpanTrackingInfo();

            SpanPathInfo currentInfo = _currentSpanPath.Peek();

            if (currentInfo.Children != null)
            {
                // The current SpanPathInfo instance on the top of the span path stack indicates
                // which navigation properties should be retrieved from this Entity-typed expression
                // and also specifies (in the form of child SpanPathInfo instances) which sub-paths
                // must be expanded for each of those navigation properties.
                // The SpanPathInfo instance may be the root instance or a SpanPathInfo that represents a sub-path.
                int idx = 1; // SpanRoot is always the first (zeroth) column, full- and relationship-span columns follow.
                foreach (KeyValuePair <NavigationProperty, SpanPathInfo> nextInfo in currentInfo.Children)
                {
                    // If the tracking information was not initialized yet, do so now.
                    if (null == tracking.ColumnDefinitions)
                    {
                        tracking = InitializeTrackingInfo(this.RelationshipSpan);
                    }

                    // Create a property expression that retrieves the specified navigation property from the Entity-typed expression.
                    // Note that the expression is cloned since it may be used as the instance of multiple property expressions.
                    DbExpression columnDef = expression.Property(nextInfo.Key);

                    // Rewrite the result of the navigation property. This is required for two reasons:
                    // 1. To continue spanning the current Include path.
                    // 2. To apply relationship span to the Entity or EntityCollection produced by the navigation property, if necessary.
                    //    Consider an Include path of "Order" for a query that returns OrderLines - the Include'd Orders should have
                    //    their associated Customer relationship spanned.
                    // Note that this will recursively call this method with the Entity type of the result of the
                    // navigation property, which will in turn call loop through the sub-paths of this navigation
                    // property and adjust the stack to track which Include path is being expanded and which
                    // element of that path is considered 'current'.
                    _currentSpanPath.Push(nextInfo.Value);
                    columnDef = this.Rewrite(columnDef);
                    _currentSpanPath.Pop();

                    // Add a new column to the tracked columns using the rewritten column definition
                    tracking.ColumnDefinitions.Add(new KeyValuePair <string, DbExpression>(tracking.ColumnNames.Next(), columnDef));
                    AssociationEndMember targetEnd = GetNavigationPropertyTargetEnd(nextInfo.Key);
                    tracking.SpannedColumns[idx] = targetEnd;

                    // If full span and relationship span are both required, a relationship span may be rendered
                    // redundant by an already added full span. Therefore the association ends that have been expanded
                    // as part of full span are tracked using a dictionary.
                    if (this.RelationshipSpan)
                    {
                        tracking.FullSpannedEnds[targetEnd] = true;
                    }

                    idx++;
                }
            }

            return(tracking);
        }
예제 #2
0
        private void ConvertSpanPath(SpanPathInfo parentInfo, List <string> navPropNames, int pos)
        {
            // Attempt to retrieve the next navigation property from the current entity type
            // using the name of the current navigation property in the Include path.
            NavigationProperty nextNavProp = null;

            if (!parentInfo.DeclaringType.NavigationProperties.TryGetValue(navPropNames[pos], true, out nextNavProp))
            {
                // The navigation property name is not valid for this Entity type
                throw new InvalidOperationException(
                          Strings.ObjectQuery_Span_NoNavProp(parentInfo.DeclaringType.FullName, navPropNames[pos]));
            }

            // The navigation property was retrieved, an entry for it must be ensured in the Children
            // collection of the parent SpanPathInfo instance.
            // If the parent's Children collection does not exist then instantiate it now:
            if (null == parentInfo.Children)
            {
                parentInfo.Children = new Dictionary <NavigationProperty, SpanPathInfo>();
            }

            // If a sub-path that begins with the current navigation property name was already
            // encountered, then a SpanPathInfo for this navigation property may already exist
            // in the Children dictionary...
            SpanPathInfo nextChild = null;

            if (!parentInfo.Children.TryGetValue(nextNavProp, out nextChild))
            {
                // ... otherwise, create a new SpanPathInfo instance that this navigation
                // property maps to and ensure its presence in the Children dictionary.
                nextChild = new SpanPathInfo(EntityTypeFromResultType(nextNavProp));
                parentInfo.Children[nextNavProp] = nextChild;
            }

            // If this navigation property is not the end of the span path then
            // increment the position and recursively call ConvertSpanPath, specifying
            // the (retrieved or newly-created) SpanPathInfo of this navigation property
            // as the new 'parent' info.
            if (pos < navPropNames.Count - 1)
            {
                ConvertSpanPath(nextChild, navPropNames, pos + 1);
            }
        }
예제 #3
0
        internal ObjectFullSpanRewriter(DbCommandTree tree, DbExpression toRewrite, Span span, AliasGenerator aliasGenerator)
            : base(tree, toRewrite, aliasGenerator)
        {
            DebugCheck.NotNull(span);
            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);
        }
        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);
        }
예제 #5
0
 /// <summary>
 ///     Populates the Include span tree with appropriate branches for the Include path
 ///     represented by the specified list of navigation property names.
 /// </summary>
 /// <param name="parentInfo"> The root SpanPathInfo </param>
 /// <param name="navPropNames"> A list of navigation property names that describes a single Include span path </param>
 private void AddSpanPath(SpanPathInfo parentInfo, List <string> navPropNames)
 {
     ConvertSpanPath(parentInfo, navPropNames, 0);
 }
        private void ConvertSpanPath(SpanPathInfo parentInfo, List<string> navPropNames, int pos)
        {
            // Attempt to retrieve the next navigation property from the current entity type
            // using the name of the current navigation property in the Include path.
            NavigationProperty nextNavProp = null;
            if (!parentInfo.DeclaringType.NavigationProperties.TryGetValue(navPropNames[pos], true, out nextNavProp))
            {
                // The navigation property name is not valid for this Entity type
                throw new InvalidOperationException(
                    Strings.ObjectQuery_Span_NoNavProp(parentInfo.DeclaringType.FullName, navPropNames[pos]));
            }

            // The navigation property was retrieved, an entry for it must be ensured in the Children
            // collection of the parent SpanPathInfo instance.
            // If the parent's Children collection does not exist then instantiate it now:
            if (null == parentInfo.Children)
            {
                parentInfo.Children = new Dictionary<NavigationProperty, SpanPathInfo>();
            }

            // If a sub-path that begins with the current navigation property name was already
            // encountered, then a SpanPathInfo for this navigation property may already exist
            // in the Children dictionary...
            SpanPathInfo nextChild = null;
            if (!parentInfo.Children.TryGetValue(nextNavProp, out nextChild))
            {
                // ... otherwise, create a new SpanPathInfo instance that this navigation
                // property maps to and ensure its presence in the Children dictionary.
                nextChild = new SpanPathInfo(EntityTypeFromResultType(nextNavProp));
                parentInfo.Children[nextNavProp] = nextChild;
            }

            // If this navigation property is not the end of the span path then
            // increment the position and recursively call ConvertSpanPath, specifying
            // the (retrieved or newly-created) SpanPathInfo of this navigation property
            // as the new 'parent' info.
            if (pos < navPropNames.Count - 1)
            {
                ConvertSpanPath(nextChild, navPropNames, pos + 1);
            }
        }
 /// <summary>
 ///     Populates the Include span tree with appropriate branches for the Include path
 ///     represented by the specified list of navigation property names.
 /// </summary>
 /// <param name="parentInfo"> The root SpanPathInfo </param>
 /// <param name="navPropNames"> A list of navigation property names that describes a single Include span path </param>
 private void AddSpanPath(SpanPathInfo parentInfo, List<string> navPropNames)
 {
     ConvertSpanPath(parentInfo, navPropNames, 0);
 }