/// <summary>
        /// Write the property access token as URI part to this builder.
        /// </summary>
        /// <param name="propertyAccess">To write as URI part.</param>
        protected virtual void WritePropertyAccess(PropertyAccessQueryToken propertyAccess)
        {
            ExceptionUtils.CheckArgumentNotNull(propertyAccess, "propertyAccess");

            if (propertyAccess.Parent != null)
            {
                this.WriteQuery(propertyAccess.Parent);
                this.builder.Append(ExpressionConstants.SymbolForwardSlash);
            }

            this.builder.Append(propertyAccess.Name);
        }
        /// <summary>
        /// Binds a property access token.
        /// </summary>
        /// <param name="propertyAccessToken">The property access token to bind.</param>
        /// <returns>The bound property access token.</returns>
        protected virtual QueryNode BindPropertyAccess(PropertyAccessQueryToken propertyAccessToken)
        {
            ExceptionUtils.CheckArgumentNotNull(propertyAccessToken, "propertyAccessToken");
            ExceptionUtils.CheckArgumentStringNotNullOrEmpty(propertyAccessToken.Name, "propertyAccessToken.Name");

            SingleValueQueryNode parentNode;
            SingleValueQueryNode navigationPath = null;

            // Set the parentNode (get the parent type, so you can check whether the Name inside propertyAccessToken really is legit offshoot of the parent type)
            QueryNode parent = null;
            if (propertyAccessToken.Parent == null)
            {
                if (this.parameter == null)
                {
                    throw new ODataException(Strings.MetadataBinder_PropertyAccessWithoutParentParameter);
                }

                parentNode = this.parameter;
                parent = this.parameter;
            }
            else
            {
                    parent = this.Bind(propertyAccessToken.Parent) as SingleValueQueryNode;
                    if (parent == null)
                    {
                        throw new ODataException(Strings.MetadataBinder_PropertyAccessSourceNotSingleValue(propertyAccessToken.Name));
                    }

                    NavigationPropertyNode parentNav = parent as NavigationPropertyNode;
                    CastNode parentCast = parent as CastNode;
                    PropertyAccessQueryNode parentProperty = parent as PropertyAccessQueryNode;

                    if (parentProperty != null)
                    {
                        navigationPath = parentProperty;
                        var propertyPath = (IEdmStructuralProperty)parentProperty.Property;
                        parentNode = new ParameterQueryNode()
                                         {
                                             ParameterType = propertyPath.Type
                                         };
                    }
                    else if (parentCast != null)
                    {
                        IEdmType entityType = parentCast.EdmType;
                        parentNode = new ParameterQueryNode()
                        {
                            ParameterType = entityType.ToTypeReference()
                        };
                    }
                    else if (parentNav != null)
                    {
                        navigationPath = parentNav;
                        IEdmEntityType entityType = parentNav.NavigationProperty.ToEntityType();
                        parentNode = new ParameterQueryNode()
                        {
                            ParameterType = new EdmEntityTypeReference(entityType, true)
                        };
                    }
                    else
                    {
                        parentNode = this.Bind(propertyAccessToken.Parent) as SingleValueQueryNode;
                    }
            }

            // Now that we have the parent type, can find its corresponding EDM type
            IEdmStructuredTypeReference structuredParentType =
                parentNode.TypeReference == null ? null : parentNode.TypeReference.AsStructuredOrNull();
            IEdmProperty property =
                structuredParentType == null ? null : structuredParentType.FindProperty(propertyAccessToken.Name);

            if (property != null)
            {
                // TODO: Check that we have entity set once we add the entity set propagation into the bound tree
                // See RequestQueryParser.ExpressionParser.ParseMemberAccess
                if (property.Type.IsNonEntityODataCollectionTypeKind())
                {
                    throw new ODataException(Strings.MetadataBinder_MultiValuePropertyNotSupportedInExpression(property.Name));
                }

                if (property.PropertyKind == EdmPropertyKind.Navigation)
                {
                    // TODO: Implement navigations
                    throw new NotImplementedException();
                }

                if (navigationPath != null)
                {
                    parentNode = navigationPath;
                }

                return new PropertyAccessQueryNode()
                {
                    Source = (SingleValueQueryNode)parent,
                    Property = property
                };
            }
            else
            {
                if (parentNode.TypeReference != null && !parentNode.TypeReference.Definition.IsOpenType())
                {
                    throw new ODataException(Strings.MetadataBinder_PropertyNotDeclared(parentNode.TypeReference.ODataFullName(), propertyAccessToken.Name));
                }

                // TODO: Implement open property support
                throw new NotImplementedException();
            }
        }
        /// <summary>
        /// Binds a property access token.
        /// </summary>
        /// <param name="propertyAccessToken">The property access token to bind.</param>
        /// <returns>The bound property access token.</returns>
        protected virtual QueryNode BindPropertyAccess(PropertyAccessQueryToken propertyAccessToken)
        {
            ExceptionUtils.CheckArgumentNotNull(propertyAccessToken, "propertyAccessToken");
            ExceptionUtils.CheckArgumentStringNotNullOrEmpty(propertyAccessToken.Name, "propertyAccessToken.Name");

            SingleValueQueryNode parentNode;
            if (propertyAccessToken.Parent == null)
            {
                if (this.parameter == null)
                {
                    throw new ODataException(Strings.MetadataBinder_PropertyAccessWithoutParentParameter);
                }

                parentNode = this.parameter;
            }
            else
            {
                // TODO: Do we really want to fail with cast exception if the parent is a collection (for example)?
                parentNode = this.Bind(propertyAccessToken.Parent) as SingleValueQueryNode;
                if (parentNode == null)
                {
                    throw new ODataException(Strings.MetadataBinder_PropertyAccessSourceNotSingleValue(propertyAccessToken.Name));
                }
            }

            ResourceProperty property = parentNode.ResourceType == null ?
                null : parentNode.ResourceType.TryResolvePropertyName(propertyAccessToken.Name);

            if (property != null)
            {
                // TODO: Check that we have resourceset once we add the resource set propagation into the bound tree
                // See RequestQueryParser.ExpressionParser.ParseMemberAccess
                if (property.Kind == ResourcePropertyKind.MultiValue)
                {
                    throw new ODataException(Strings.MetadataBinder_MultiValuePropertyNotSupportedInExpression(property.Name));
                }

                if (property.Kind == ResourcePropertyKind.ResourceReference || property.Kind == ResourcePropertyKind.ResourceSetReference)
                {
                    // TODO: Implement navigations
                    throw new NotImplementedException();
                }

                return new PropertyAccessQueryNode()
                {
                    Source = parentNode,
                    Property = property
                };
            }
            else
            {
                if (parentNode.ResourceType != null && !parentNode.ResourceType.IsOpenType)
                {
                    throw new ODataException(Strings.MetadataBinder_PropertyNotDeclared(parentNode.ResourceType.FullName, propertyAccessToken.Name));
                }

                // TODO: Implement open property support
                throw new NotImplementedException();
            }
        }
        /// <summary>
        /// Write the property access token as URI part to this builder.
        /// </summary>
        /// <param name="propertyAccess">To write as URI part.</param>
        protected virtual void WritePropertyAccess(PropertyAccessQueryToken propertyAccess)
        {
            ExceptionUtils.CheckArgumentNotNull(propertyAccess, "propertyAccess");

            if (propertyAccess.Parent != null)
            {
                this.WriteQuery(propertyAccess.Parent);
                this.builder.Append(ExpressionConstants.SymbolForwardSlash);
            }

            this.builder.Append(propertyAccess.Name);
        }