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); }
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); } }
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); }
/// <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); }