/// <summary>
        /// Add a projection to the query.
        /// </summary>
        /// <param name="expression">Select method call expression.</param>
        private void AddProjection(MethodCallExpression expression)
        {
            // We only support Select(x => ...) projections.  Anything else
            // will throw a NotSupportException.
            if (expression != null && expression.Arguments.Count == 2)
            {
                LambdaExpression projection = StripQuote(expression.Arguments[1]) as LambdaExpression;
                if (projection != null && projection.Parameters.Count == 1)
                {
                    // Store the type of the input to the projection as we'll
                    // need that for deserialization of values (since the
                    // projection will change the expected type of the data
                    // source)
                    this.query.ProjectionArgumentType = projection.Parameters[0].Type;

                    // Compile the projection into a function that we can apply
                    // to the deserialized value to transform it accordingly.
                    this.query.Projection = projection.Compile();

                    // Filter the selection down to just the values used by
                    // the projection
                    VisitorHelper.VisitMembers(
                        projection.Body,
                        (expr, recur) =>
                    {
                        // Ensure we only process members of the parameter
                        if (expr != null && expr.Expression.NodeType == ExpressionType.Parameter)
                        {
                            SerializableMember member = SerializableType.GetMember(expr.Member);
                            if (member != null)
                            {
                                query.Selection.Add(member.Name);
                            }
                        }
                        return(recur(expr));
                    });

                    // Make sure we also include all the members that would be
                    // required for deserialization
                    foreach (SerializableMember member in
                             SerializableType.Get(this.query.ProjectionArgumentType)
                             .Members
                             .Select(p => p.Value)
                             .Where(m => m.IsRequired))
                    {
                        if (!this.query.Selection.Contains(member.Name))
                        {
                            this.query.Selection.Add(member.Name);
                        }
                    }

                    return;
                }
            }

            ThrowForUnsupportedException(expression);
        }
        /// <summary>
        /// Get the table member referenced by an expression or return null.
        /// </summary>
        /// <param name="expression">The expression to check.</param>
        /// <returns>The table member or null.</returns>
        protected static SerializableMember GetTableMember(Expression expression)
        {
            // Only parameter references are valid in a query (any other
            // references should have been partially evaluated away)
            MemberExpression member = expression as MemberExpression;

            if (member != null &&
                member.Expression != null &&
                member.Expression.NodeType == ExpressionType.Parameter &&
                member.Member != null)
            {
                // Lookup the Mobile Services name of the member and use that
                return(SerializableType.GetMember(member.Member));
            }

            // Otherwise return null
            return(null);
        }
        /// <summary>
        /// Add an ordering constraint for an OrderBy/ThenBy call.
        /// </summary>
        /// <param name="expression">The ordering method call.</param>
        /// <param name="ascending">
        /// Whether the order is ascending or descending.
        /// </param>
        private void AddOrdering(MethodCallExpression expression, bool ascending)
        {
            // Keep updating with the deepest nested expression structure we
            // can get to so that we can provide a more detailed error message
            Expression deepest = expression;

            // We only allow OrderBy(x => x.Member) expressions.  Anything else
            // will result in a NotSupportedException.
            if (expression != null && expression.Arguments.Count >= 2)
            {
                LambdaExpression lambda = StripQuote(expression.Arguments[1]) as LambdaExpression;
                if (lambda != null)
                {
                    deepest = lambda.Body ?? lambda;

                    // Find the name of the member being ordered
                    MemberExpression memberAccess = lambda.Body as MemberExpression;
                    if (memberAccess != null)
                    {
                        if (memberAccess.Expression.NodeType == ExpressionType.Parameter)
                        {
                            SerializableMember member = SerializableType.GetMember(memberAccess.Member);
                            if (member != null && member.Name != null)
                            {
                                // Add the ordering
                                this.query.Ordering.Add(new KeyValuePair <string, bool>(member.Name, ascending));
                                return;
                            }
                        }
                    }
                }
            }

            throw new NotSupportedException(
                      string.Format(
                          CultureInfo.InvariantCulture,
                          Resources.MobileServiceTableQueryTranslator_GetOrdering_Unsupported,
                          expression != null && expression.Method != null ? expression.Method.Name : null,
                          deepest != null ? deepest.ToString() : null));
        }