ExpandedProjectionNode.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / DataWeb / Server / System / Data / Services / Providers / ExpandedProjectionNode.cs / 1407647 / ExpandedProjectionNode.cs

                            //---------------------------------------------------------------------- 
// 
//      Copyright (c) Microsoft Corporation.  All rights reserved.
// 
//  
//      Represents an expanded node in the tree of projections
//      for queries with $expand and/or $select. 
//  
//
// @owner  [....] 
//---------------------------------------------------------------------

namespace System.Data.Services.Providers
{ 
    #region Namespaces
    using System; 
    using System.Collections.Generic; 
    using System.Diagnostics;
    using System.Linq; 
    using System.Linq.Expressions;
    #endregion

    /// This class represents an expanded navigation property in the tree 
    /// of projected properties. It is also used to represent the root of the projection tree.
    [DebuggerDisplay("ExpandedProjectionNode {PropertyName}")] 
    internal class ExpandedProjectionNode : ProjectionNode 
    {
        #region Private fields 
        /// The resource set to which the expansion leads.
        /// If this node represents expanded navigation property, this is the resource set
        /// to which the expanded navigation property points to.
        /// If this node is the root node of the projection tree, this is the resource set 
        /// for the root of the query results.
        private readonly ResourceSetWrapper resourceSetWrapper; 
 
        /// Collection of information which describes the ordering for the results
        /// returned by this expanded property. 
        /// This can be null in which case no ordering is to be applied.
        private readonly OrderingInfo orderingInfo;

        /// The filter expression to be applied to results returned by this expanded property. 
        /// This can be null in which case no filter is to be applied.
        private readonly Expression filter; 
 
        /// Number of results to skip for this node.
        /// null value means that no skip should be applied. 
        private readonly int? skipCount;

        /// Maximum number of results to return for this node.
        /// null value means that all results should be returned. 
        private readonly int? takeCount;
 
        /// Maximum number of results allowed for this node. Provider should use this only as a hint. 
        /// It should return no less then maxResultsExpected + 1 results (assuming that number is available)
        /// so that the service can detect violation of the limit. 
        /// null value means that no limit will be applied and thus all results available should be returned.
        private readonly int? maxResultsExpected;

        /// List of child nodes. 
        private List nodes;
 
        /// Internal field which is set to true once we have seen a projection including this expanded 
        /// property. Otherwise set to false.
        /// This field is used to eliminate expanded nodes which are not projected and thus there 
        /// would be no point in expanding them.
        private bool projectionFound;

        /// Flag which specifies if all child properties of this node should be projected. 
        private bool projectAllImmediateProperties;
 
        /// Flag which specified is the entire expanded subtree of this node should be projected. 
        private bool projectSubtree;
        #endregion 

        #region Constructors
        /// Creates new instance of node representing expanded navigation property.
        /// The name of the property to project and expand. 
        /// The  for this property. Can only be null for the root node.
        /// The resource set to which the expansion leads. 
        /// The ordering info for this node. null means no ordering to be applied. 
        /// The filter for this node. null means no filter to be applied.
        /// Number of results to skip. null means no results to be skipped. 
        /// Maximum number of results to return. null means return all available results.
        /// Maximum number of expected results. Hint that the provider should return
        /// at least maxResultsExpected + 1 results (if available).
        internal ExpandedProjectionNode( 
            string propertyName,
            ResourceProperty property, 
            ResourceSetWrapper resourceSetWrapper, 
            OrderingInfo orderingInfo,
            Expression filter, 
            int? skipCount,
            int? takeCount,
            int? maxResultsExpected)
            : base(propertyName, property) 
        {
            Debug.Assert(resourceSetWrapper != null, "resourceSetWrapper != null"); 
            Debug.Assert(property != null || propertyName.Length == 0, "We don't support open navigation properties."); 

            this.resourceSetWrapper = resourceSetWrapper; 
            this.orderingInfo = orderingInfo;
            this.filter = filter;
            this.skipCount = skipCount;
            this.takeCount = takeCount; 
            this.maxResultsExpected = maxResultsExpected;
            this.nodes = new List(); 
        } 
        #endregion
 
        #region Public properties
        /// Collection of information which describes the ordering for the results
        /// returned by this expanded property.
        /// This can be null in which case no ordering is to be applied. 
        public OrderingInfo OrderingInfo
        { 
            get 
            {
                return this.orderingInfo; 
            }
        }

        /// The filter expression to be applied to results returned by this expanded property. 
        /// This can be null in which case no filter is to be applied.
        public Expression Filter 
        { 
            get
            { 
                return this.filter;
            }
        }
 
        /// Number of results to skip for this node.
        /// null value means that no skip should be applied. 
        public int? SkipCount 
        {
            get 
            {
                return this.skipCount;
            }
        } 

        /// Maximum number of results to return for this node. 
        /// null value means that all results should be returned. 
        public int? TakeCount
        { 
            get
            {
                return this.takeCount;
            } 
        }
 
        /// Maximum number of results allowed for this node. Provider should use this only as a hint. 
        /// It should return no less then MaxResultsExpected + 1 results (assuming that number is available)
        /// so that the service can detect violation of the limit. 
        /// null value means that no limit will be applied and thus all results available should be returned.
        public int? MaxResultsExpected
        {
            get 
            {
                return this.maxResultsExpected; 
            } 
        }
 
        /// List of child nodes.
        public IEnumerable Nodes
        {
            get 
            {
                return this.nodes; 
            } 
        }
 
        /// Set to true if all properties of this node should be made part of the results.
        public bool ProjectAllProperties
        {
            get 
            {
                return this.projectSubtree || this.ProjectAllImmediateProperties; 
            } 
        }
        #endregion 

        #region Internal properties
        /// The resource set to which the expansion leads.
        /// If this node represents expanded navigation property, this is the resource set 
        /// to which the expanded navigation property points to.
        /// If this node is the root node of the projection tree, this is the resource set 
        /// for the root of the query results. 
        /// This property is for internal use by components of the WCF Data Services
        /// to avoid unnecessary lookups of the wrapper from the ResourceSet property. 
        internal ResourceSetWrapper ResourceSetWrapper
        {
            get
            { 
                return this.resourceSetWrapper;
            } 
        } 

        /// The resource type in which all the entities expanded by this segment will be of. 
        /// This is usually the resource type of the  for this node,
        /// but it can also be a derived type of that resource type.
        /// This can happen if navigation property points to a resource set but uses a derived type.
        /// It can also happen if service operation returns entities from a given resource set 
        /// but it returns derived types.
        internal virtual ResourceType ResourceType 
        { 
            get
            { 
                Debug.Assert(this.Property != null, "Derived class should override this if property can be null.");
                return this.Property.ResourceType;
            }
        } 

        /// Internal property which is set to true once we have seen a projection including this expanded 
        /// property. Otherwise set to false. 
        /// This property is used to eliminate expanded nodes which are not projected and thus there
        /// would be no point in expanding them. 
        internal bool ProjectionFound
        {
            get
            { 
                return this.projectionFound;
            } 
 
            set
            { 
                this.projectionFound = value;
            }
        }
 
        /// Flag which specifies if all child properties of this node should be projected.
        internal bool ProjectAllImmediateProperties 
        { 
            get
            { 
                return this.projectAllImmediateProperties;
            }

            set 
            {
                Debug.Assert(!value || this.projectionFound, "Marking node to include all child properties requires the node to be projected."); 
                this.projectAllImmediateProperties = value; 
            }
        } 

        /// Whether this expanded node has a filter or a constraint on max results returns.
        internal bool HasFilterOrMaxResults
        { 
            get
            { 
                return this.Filter != null || this.MaxResultsExpected.HasValue; 
            }
        } 

        #endregion

        #region Internal methods 
        /// Find a child node of a given property.
        /// The name of the property to find the child for. 
        /// The child node if there's one for the specified  or null 
        /// if no such child was found.
        internal ProjectionNode FindNode(string propertyName) 
        {
            Debug.Assert(propertyName != null, "propertyName != null");
            return this.nodes.FirstOrDefault(
                projectionNode => String.Equals(projectionNode.PropertyName, propertyName, StringComparison.Ordinal)); 
        }
 
        /// Adds a new child node to this node. 
        /// The child node to add.
        internal void AddNode(ProjectionNode node) 
        {
            Debug.Assert(node != null, "node != null");
            Debug.Assert(this.FindNode(node.PropertyName) == null, "Trying to add a duplicate node.");
            this.nodes.Add(node); 
        }
 
        /// Walks the subtree of this node and removes all nodes which were not marked projected. 
        /// Used to remove unnecessary expanded nodes.
        internal void RemoveNonProjectedNodes() 
        {
            for (int j = this.nodes.Count - 1; j >= 0; j--)
            {
                ExpandedProjectionNode expandedNode = this.nodes[j] as ExpandedProjectionNode; 

                // Leave non-expanded properties there as they specify projections. 
                if (expandedNode == null) 
                {
                    continue; 
                }

                // If we are to project entire subtree, leave all expanded nodes in as well
                // otherwise remove the expanded nodes which are not marked as projected. 
                if (!this.projectSubtree && !expandedNode.ProjectionFound)
                { 
                    // This removes the expandedNode from the tree (and all its children) 
                    this.nodes.RemoveAt(j);
                } 
                else
                {
                    expandedNode.RemoveNonProjectedNodes();
                } 
            }
        } 
 
        /// Removes duplicates from the tree caused by wildcards and sorts the projected properties.
        ///  
        /// Examples
        /// $select=Orders, Orders/ID           - get rid of the Orders/ID
        /// $select=Orders, Orders/*            - get rid of the Orders/*
        /// $select=Orders/*, Orders/ID         - get rid of the Orders/ID 
        /// $select=Orders/*, Orders/OrderItems&$expand=Orders - get rid of the Orders/OrderItems (it's redundant to *)
        /// $select=Orders/*, Orders/OrderItems&$expand=Orders/OrderItems - leave as is, the Orders/OrderItems are expanded 
        /// 
        /// The sorting order is the same as the order in which the properties are enumerated on the owning type.
        /// This is to preserve the same order as if no projections occured. 
        /// 
        internal void ApplyWildcardsAndSort()
        {
            // If this segment was marked to include entire subtree 
            // simply remove all children which are not expanded
            // and propagate the information to all expanded children. 
            if (this.projectSubtree) 
            {
                for (int j = this.nodes.Count - 1; j >= 0; j--) 
                {
                    ExpandedProjectionNode expandedNode = this.nodes[j] as ExpandedProjectionNode;
                    if (expandedNode != null)
                    { 
                        expandedNode.projectSubtree = true;
                        expandedNode.ApplyWildcardsAndSort(); 
                    } 
                    else
                    { 
                        this.nodes.RemoveAt(j);
                    }
                }
 
                this.projectAllImmediateProperties = false;
                return; 
            } 

            for (int j = this.nodes.Count - 1; j >= 0; j--) 
            {
                ExpandedProjectionNode expandedNode = this.nodes[j] as ExpandedProjectionNode;

                // If this node was marked to include all immediate properties, 
                //   remove all children which are not expanded.
                //   That means they are either simple properties or nav. properties which 
                //   are not going to be expanded anyway. 
                if (this.ProjectAllImmediateProperties && expandedNode == null)
                { 
                    this.nodes.RemoveAt(j);
                }
                else if (expandedNode != null)
                { 
                    expandedNode.ApplyWildcardsAndSort();
                } 
            } 

            if (this.nodes.Count > 0) 
            {
                // Sort the subsegments such that they have the same order as the properties
                //   on the owning resource type.
                ResourceType resourceType = this.ResourceType; 

                List existingNodes = this.nodes; 
                this.nodes = new List(existingNodes.Count); 
                foreach (ResourceProperty property in resourceType.Properties)
                { 
                    Debug.Assert(
                        existingNodes.Where(node => node.Property == property).Count() <= 1,
                        "Can't have more than one projection segment for a given property.");
                    ProjectionNode projectionNode = existingNodes.FirstOrDefault( 
                        node => node.Property == property);
                    if (projectionNode != null) 
                    { 
                        this.nodes.Add(projectionNode);
                    } 
                }

                // And then append any open properties sorted alphabetically
                // We sort these since we don't want client to be able to influence 
                //   the server behavior unless abo----ely necessary.
                List openPropertyProjectionNodes = 
                    existingNodes.Where(node => node.Property == null).ToList(); 
                openPropertyProjectionNodes.Sort(new Comparison((x, y) =>
                { 
                    return String.Compare(x.PropertyName, y.PropertyName, StringComparison.Ordinal);
                }));
                this.nodes.AddRange(openPropertyProjectionNodes);
                Debug.Assert(this.nodes.Count == existingNodes.Count, "We didn't sort all the properties."); 
            }
        } 
 
        /// Marks the entire subtree as projected.
        /// This is used when there were no projections specified in the query 
        /// to mark the entire tree as projected.
        internal void MarkSubtreeAsProjected()
        {
            this.projectSubtree = true; 
            this.projectAllImmediateProperties = false;
 
            foreach (ProjectionNode node in this.nodes) 
            {
                ExpandedProjectionNode expandedNode = node as ExpandedProjectionNode; 
                if (expandedNode != null)
                {
                    expandedNode.MarkSubtreeAsProjected();
                } 
            }
        } 
        #endregion 
    }
} 

// 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