ObjectFullSpanRewriter.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Dotnetfx_Win7_3.5.1 / Dotnetfx_Win7_3.5.1 / 3.5.1 / DEVDIV / depot / DevDiv / releases / Orcas / NetFXw7 / ndp / fx / src / DataEntity / System / Data / Objects / Internal / ObjectFullSpanRewriter.cs / 1 / ObjectFullSpanRewriter.cs

                            //---------------------------------------------------------------------- 
// 
//      Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// 
// @owner [....]
// @backupowner [....] 
//--------------------------------------------------------------------- 

using System; 
using System.Collections.Generic;
using System.Diagnostics;
using System.Data.Common;
using System.Data.Common.Utils; 
using System.Data.Metadata.Edm;
using System.Data.Common.CommandTrees; 
using System.Data.Objects.DataClasses; 
using System.Text;
 
namespace System.Data.Objects.Internal
{
    internal class ObjectFullSpanRewriter : ObjectSpanRewriter
    { 
        /// 
        /// Represents a node in the 'Include' navigation property tree 
        /// built from the list of SpanPaths on the Span object with which 
        /// the FullSpanRewriter is constructed.
        ///  
        private class SpanPathInfo
        {
            internal SpanPathInfo(EntityType declaringType)
            { 
                this.DeclaringType = declaringType;
            } 
 
            /// 
            /// The effective Entity type of this node in the tree 
            /// 
            internal EntityType DeclaringType;

            ///  
            /// Describes the navigation properties that should be retrieved
            /// from this node in the tree and the Include sub-paths that extend 
            /// from each of those navigation properties 
            /// 
            internal Dictionary Children; 
        }

        /// 
        /// Maintains a reference to the SpanPathInfo tree node representing the 
        /// current position in the 'Include' path that is currently being expanded.
        ///  
        private Stack _currentSpanPath = new Stack(); 

        internal ObjectFullSpanRewriter(DbExpression toRewrite, Span span) 
            : base(toRewrite)
        {
            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 that produced 
            // the Command Tree that is being rewritten. This could be either 
            // literally 'T' or Collection.
            EntityType entityType = null; 
            if (!TryGetEntityType(this.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 EntityUtil.InvalidOperation(System.Data.Entity.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.
            SpanPathInfo 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 (Span.SpanPath 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); 
        }
 
        /// 
        /// Populates the Include span tree with appropriate branches for the Include path
        /// represented by the specified list of navigation property names.
        ///  
        /// The root SpanPathInfo
        /// A list of navigation property names that describes a single Include span path 
        private void AddSpanPath(SpanPathInfo parentInfo, List navPropNames) 
        {
            ConvertSpanPath(parentInfo, navPropNames, 0); 
        }

        private void ConvertSpanPath(SpanPathInfo parentInfo, List 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 EntityUtil.InvalidOperation(System.Data.Entity.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();
            }

            // 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); 
            }
        } 
 
        /// 
        /// Retrieves the Entity (result or element) type produced by a Navigation Property. 
        /// 
        /// The navigation property
        /// 
        ///     The Entity type produced by the navigation property. 
        ///     This may be the immediate result type (if the result is at most one)
        ///     or the element type of the result type, otherwise. 
        ///  
        private static EntityType EntityTypeFromResultType(NavigationProperty navProp)
        { 
            EntityType retType = null;
            TryGetEntityType(navProp.TypeUsage, out retType);
            // Currently, navigation properties may only return an Entity or Collection result
            Debug.Assert(retType != null, "Navigation property has non-Entity and non-Entity collection result type?"); 
            return retType;
        } 
 
        /// 
        /// Retrieves the Entity (result or element) type referenced by the specified TypeUsage, if 
        /// its EdmType is an Entity type or a collection type with an Entity element type.
        /// 
        /// The TypeUsage that provides the EdmType to examine
        /// The referenced Entity (element) type, if present. 
        /// 
        ///     true if the specified  is an Entity type or a 
        ///     collection type with an Entity element type; otherwise false. 
        /// 
        private static bool TryGetEntityType(TypeUsage resultType, out EntityType entityType) 
        {
            // If the result type is an Entity, then simply use that type.
            if (BuiltInTypeKind.EntityType == resultType.EdmType.BuiltInTypeKind)
            { 
                entityType = (EntityType)resultType.EdmType;
                return true; 
            } 
            else if (BuiltInTypeKind.CollectionType == resultType.EdmType.BuiltInTypeKind)
            { 
                // If the result type of the query is a collection, attempt to extract
                // the element type of the collection and determine if it is an Entity type.
                EdmType elementType = ((CollectionType)resultType.EdmType).TypeUsage.EdmType;
                if (BuiltInTypeKind.EntityType == elementType.BuiltInTypeKind) 
                {
                    entityType = (EntityType)elementType; 
                    return true; 
                }
            } 

            entityType = null;
            return false;
        } 

        ///  
        /// Utility method to retrieve the 'To' AssociationEndMember of a NavigationProperty 
        /// 
        /// The navigation property 
        /// The AssociationEndMember that is the target of the navigation operation represented by the NavigationProperty
        private AssociationEndMember GetNavigationPropertyTargetEnd(NavigationProperty property)
        {
            AssociationType relationship = this.Metadata.GetItem(property.RelationshipType.FullName, DataSpace.CSpace); 
            Debug.Assert(relationship.AssociationEndMembers.Contains(property.ToEndMember.Name), "Association does not declare member referenced by Navigation property?");
            return relationship.AssociationEndMembers[property.ToEndMember.Name]; 
        } 

        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 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.CommandTree.CreatePropertyExpression(nextInfo.Key, expression.Clone());
 
                    // 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(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;
        }
    }
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
//---------------------------------------------------------------------- 
// 
//      Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// 
// @owner [....]
// @backupowner [....] 
//--------------------------------------------------------------------- 

using System; 
using System.Collections.Generic;
using System.Diagnostics;
using System.Data.Common;
using System.Data.Common.Utils; 
using System.Data.Metadata.Edm;
using System.Data.Common.CommandTrees; 
using System.Data.Objects.DataClasses; 
using System.Text;
 
namespace System.Data.Objects.Internal
{
    internal class ObjectFullSpanRewriter : ObjectSpanRewriter
    { 
        /// 
        /// Represents a node in the 'Include' navigation property tree 
        /// built from the list of SpanPaths on the Span object with which 
        /// the FullSpanRewriter is constructed.
        ///  
        private class SpanPathInfo
        {
            internal SpanPathInfo(EntityType declaringType)
            { 
                this.DeclaringType = declaringType;
            } 
 
            /// 
            /// The effective Entity type of this node in the tree 
            /// 
            internal EntityType DeclaringType;

            ///  
            /// Describes the navigation properties that should be retrieved
            /// from this node in the tree and the Include sub-paths that extend 
            /// from each of those navigation properties 
            /// 
            internal Dictionary Children; 
        }

        /// 
        /// Maintains a reference to the SpanPathInfo tree node representing the 
        /// current position in the 'Include' path that is currently being expanded.
        ///  
        private Stack _currentSpanPath = new Stack(); 

        internal ObjectFullSpanRewriter(DbExpression toRewrite, Span span) 
            : base(toRewrite)
        {
            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 that produced 
            // the Command Tree that is being rewritten. This could be either 
            // literally 'T' or Collection.
            EntityType entityType = null; 
            if (!TryGetEntityType(this.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 EntityUtil.InvalidOperation(System.Data.Entity.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.
            SpanPathInfo 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 (Span.SpanPath 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); 
        }
 
        /// 
        /// Populates the Include span tree with appropriate branches for the Include path
        /// represented by the specified list of navigation property names.
        ///  
        /// The root SpanPathInfo
        /// A list of navigation property names that describes a single Include span path 
        private void AddSpanPath(SpanPathInfo parentInfo, List navPropNames) 
        {
            ConvertSpanPath(parentInfo, navPropNames, 0); 
        }

        private void ConvertSpanPath(SpanPathInfo parentInfo, List 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 EntityUtil.InvalidOperation(System.Data.Entity.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();
            }

            // 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); 
            }
        } 
 
        /// 
        /// Retrieves the Entity (result or element) type produced by a Navigation Property. 
        /// 
        /// The navigation property
        /// 
        ///     The Entity type produced by the navigation property. 
        ///     This may be the immediate result type (if the result is at most one)
        ///     or the element type of the result type, otherwise. 
        ///  
        private static EntityType EntityTypeFromResultType(NavigationProperty navProp)
        { 
            EntityType retType = null;
            TryGetEntityType(navProp.TypeUsage, out retType);
            // Currently, navigation properties may only return an Entity or Collection result
            Debug.Assert(retType != null, "Navigation property has non-Entity and non-Entity collection result type?"); 
            return retType;
        } 
 
        /// 
        /// Retrieves the Entity (result or element) type referenced by the specified TypeUsage, if 
        /// its EdmType is an Entity type or a collection type with an Entity element type.
        /// 
        /// The TypeUsage that provides the EdmType to examine
        /// The referenced Entity (element) type, if present. 
        /// 
        ///     true if the specified  is an Entity type or a 
        ///     collection type with an Entity element type; otherwise false. 
        /// 
        private static bool TryGetEntityType(TypeUsage resultType, out EntityType entityType) 
        {
            // If the result type is an Entity, then simply use that type.
            if (BuiltInTypeKind.EntityType == resultType.EdmType.BuiltInTypeKind)
            { 
                entityType = (EntityType)resultType.EdmType;
                return true; 
            } 
            else if (BuiltInTypeKind.CollectionType == resultType.EdmType.BuiltInTypeKind)
            { 
                // If the result type of the query is a collection, attempt to extract
                // the element type of the collection and determine if it is an Entity type.
                EdmType elementType = ((CollectionType)resultType.EdmType).TypeUsage.EdmType;
                if (BuiltInTypeKind.EntityType == elementType.BuiltInTypeKind) 
                {
                    entityType = (EntityType)elementType; 
                    return true; 
                }
            } 

            entityType = null;
            return false;
        } 

        ///  
        /// Utility method to retrieve the 'To' AssociationEndMember of a NavigationProperty 
        /// 
        /// The navigation property 
        /// The AssociationEndMember that is the target of the navigation operation represented by the NavigationProperty
        private AssociationEndMember GetNavigationPropertyTargetEnd(NavigationProperty property)
        {
            AssociationType relationship = this.Metadata.GetItem(property.RelationshipType.FullName, DataSpace.CSpace); 
            Debug.Assert(relationship.AssociationEndMembers.Contains(property.ToEndMember.Name), "Association does not declare member referenced by Navigation property?");
            return relationship.AssociationEndMembers[property.ToEndMember.Name]; 
        } 

        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 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.CommandTree.CreatePropertyExpression(nextInfo.Key, expression.Clone());
 
                    // 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(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;
        }
    }
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.

                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK