コード例 #1
0
        internal override SpanTrackingInfo CreateEntitySpanTrackingInfo(DbExpression expression, EntityType entityType)
        {
            var tracking = new SpanTrackingInfo();

            var 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.
                var idx = 1; // SpanRoot is always the first (zeroth) column, full- and relationship-span columns follow.
                foreach (var nextInfo in currentInfo.Children)
                {
                    // If the tracking information was not initialized yet, do so now.
                    if (null == tracking.ColumnDefinitions)
                    {
                        tracking = InitializeTrackingInfo(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 = 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));
                    var 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 (RelationshipSpan)
                    {
                        tracking.FullSpannedEnds[targetEnd] = true;
                    }

                    idx++;
                }
            }

            return(tracking);
        }
コード例 #2
0
        internal SpanTrackingInfo InitializeTrackingInfo(bool createAssociationEndTrackingInfo)
        {
            SpanTrackingInfo info = new SpanTrackingInfo();

            info.ColumnDefinitions = new List <KeyValuePair <string, DbExpression> >();
            info.ColumnNames       = new AliasGenerator(string.Format(CultureInfo.InvariantCulture, "Span{0}_Column", _spanCount));
            info.SpannedColumns    = new Dictionary <int, AssociationEndMember>();
            if (createAssociationEndTrackingInfo)
            {
                info.FullSpannedEnds = new Dictionary <AssociationEndMember, bool>();
            }

            return(info);
        }
コード例 #3
0
        private DbExpression RewriteEntity(DbExpression expression, EntityType entityType)
        {
            // If the expression is an Entity constructor, spanning will not produce any useful results
            // (null for an Entity/Ref navigation property, or an empty collection for a Collection
            // of Entity/Ref navigation property) since a Ref produced from the constructed Entity
            // will not indicate an Entity set, and therefore no Ref created against any Entity set
            // in the container can possibly be a match for it.
            if (DbExpressionKind.NewInstance == expression.ExpressionKind)
            {
                return(expression);
            }

            // Save the span count for later use.
            _spanCount++;
            int thisSpan = _spanCount;

            SpanTrackingInfo tracking = CreateEntitySpanTrackingInfo(expression, entityType);

            // If relationship span is required then attempt to span any appropriate relationship ends.
            List <KeyValuePair <AssociationEndMember, AssociationEndMember> > relationshipSpans = null;

            relationshipSpans = GetRelationshipSpanEnds(entityType);
            // Is the Entity type of this expression valid as the source of at least one relationship span?
            if (relationshipSpans != null)
            {
                // If the span tracking information was not initialized by CreateEntitySpanTrackingInfo,
                // then do so now as relationship span rewrites need to be tracked.
                if (null == tracking.ColumnDefinitions)
                {
                    tracking = InitializeTrackingInfo(false);
                }

                // Track column index to span information, starting at the current column count (which could be zero) plus 1.
                // 1 is added because the column containing the root entity will be added later to provide column zero.
                int idx = tracking.ColumnDefinitions.Count + 1;
                // For all applicable relationship spans that were identified...
                foreach (KeyValuePair <AssociationEndMember, AssociationEndMember> relSpan in relationshipSpans)
                {
                    // If the specified association end member was already full-spanned then the full entity
                    // will be returned in the query and there is no need to relationship-span this end to produce
                    // another result column that contains the Entity key of the full entity.
                    // Hence the relationship span is only added if there are no full-span columns or the full-span
                    // columns do not indicate that they include the target association end member of this relationship span.
                    if (null == tracking.FullSpannedEnds ||
                        !tracking.FullSpannedEnds.ContainsKey(relSpan.Value))
                    {
                        // If the source Ref is already available, because the currently spanned Entity is
                        // the result of a Relationship Navigation operation from that Ref, then use the source
                        // Ref directly rather than introducing a new Navigation operation.
                        DbExpression columnDef = null;
                        if (!TryGetNavigationSource(relSpan.Value, out columnDef))
                        {
                            // Add a new column defined by the navigation required to reach the targeted association end
                            // and update the column -> association end map to include an entry for this new column.
                            DbExpression navSource = expression.GetEntityRef();
                            columnDef = navSource.NavigateAllowingAllRelationshipsInSameTypeHierarchy(relSpan.Key, relSpan.Value);
                        }

                        tracking.ColumnDefinitions.Add(
                            new KeyValuePair <string, DbExpression>(
                                tracking.ColumnNames.Next(),
                                columnDef
                                )
                            );

                        tracking.SpannedColumns[idx] = relSpan.Value;

                        // Increment the tracked column count
                        idx++;
                    }
                }
            }

            // If no spanned columns have been added then simply return the original expression
            if (null == tracking.ColumnDefinitions)
            {
                _spanCount--;
                return(expression);
            }

            // Add the original entity-producing expression as the first (root) span column.
            tracking.ColumnDefinitions.Insert(
                0,
                new KeyValuePair <string, DbExpression>(
                    string.Format(CultureInfo.InvariantCulture, "Span{0}_SpanRoot", thisSpan),
                    expression
                    )
                );

            // Create the span row-producing NewInstanceExpression from which the span RowType can be retrieved.
            DbExpression spannedExpression = DbExpressionBuilder.NewRow(tracking.ColumnDefinitions);

            // Update the rowtype -> spaninfo map for the newly created row type instance.
            RowType spanRowType = (RowType)spannedExpression.ResultType.EdmType;

            AddSpanMap(spanRowType, tracking.SpannedColumns);

            // Return the rewritten expression
            return(spannedExpression);
        }
コード例 #4
0
        internal SpanTrackingInfo InitializeTrackingInfo(bool createAssociationEndTrackingInfo)
        {
            SpanTrackingInfo info = new SpanTrackingInfo();
            info.ColumnDefinitions = new List<KeyValuePair<string, DbExpression>>();
            info.ColumnNames = new AliasGenerator(string.Format(CultureInfo.InvariantCulture, "Span{0}_Column", _spanCount));
            info.SpannedColumns = new Dictionary<int, AssociationEndMember>();
            if (createAssociationEndTrackingInfo)
            {
                info.FullSpannedEnds = new Dictionary<AssociationEndMember, bool>();
            }

            return info;
        }
コード例 #5
0
        internal override SpanTrackingInfo CreateEntitySpanTrackingInfo(DbExpression expression, EntityType entityType)
        {
            var tracking = new SpanTrackingInfo();

            var 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.
                var idx = 1; // SpanRoot is always the first (zeroth) column, full- and relationship-span columns follow.
                foreach (var nextInfo in currentInfo.Children)
                {
                    // If the tracking information was not initialized yet, do so now.
                    if (null == tracking.ColumnDefinitions)
                    {
                        tracking = InitializeTrackingInfo(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 = 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));
                    var 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 (RelationshipSpan)
                    {
                        tracking.FullSpannedEnds[targetEnd] = true;
                    }

                    idx++;
                }
            }

            return tracking;
        }