Example #1
0
        /// <summary>
        /// Delete an instance from the table.
        /// </summary>
        /// <param name="instance">The instance to delete.</param>
        /// <returns>
        /// A task that will complete when the delete has finished.
        /// </returns>
        public async Task DeleteAsync(T instance)
        {
            if (instance == null)
            {
                throw new ArgumentNullException("instance");
            }

            // Serialize the instance
            JObject value = MobileServiceTableSerializer.Serialize(instance).AsObject();

            // Send the request
            await this.DeleteAsync(value);

            // Clear the instance ID since it's no longer associated with that
            // ID on the server (note that reflection is goodly enough to turn
            // null into the correct value for us).
            SerializableType type = SerializableType.Get(typeof(T));

            type.IdMember.SetValue(instance, null);
        }
Example #2
0
        /// <summary>
        /// Refresh the current instance with the latest values from the
        /// table.
        /// </summary>
        /// <param name="instance">The instance to refresh.</param>
        /// <returns>
        /// A task that will complete when the refresh has finished.
        /// </returns>
        public async Task RefreshAsync(T instance)
        {
            if (instance == null)
            {
                throw new ArgumentNullException("instance");
            }

            // Only refresh if it's already on the server
            SerializableType type = SerializableType.Get(typeof(T));
            object           id   = type.IdMember.GetValue(instance);

            if (!SerializableType.IsDefaultIdValue(id))
            {
                // Get the latest version of this element
                JObject obj = await this.GetSingleValueAsync(id);

                // Deserialize that value back into the current instance
                MobileServiceTableSerializer.Deserialize(obj, instance);
            }
        }
Example #3
0
        /// <summary>
        /// Delete an instance from the table.
        /// </summary>
        /// <param name="instance">The instance to delete.</param>
        /// <param name="parameters">A dictionary of user-defined parameters and values to include in the request URI query string.</param>
        /// <returns>
        /// A task that will complete when the delete has finished.
        /// </returns>
        public Task DeleteAsync(T instance, IDictionary <string, string> parameters)
        {
            if (instance == null)
            {
                throw new ArgumentNullException("instance");
            }

            // Serialize the instance
            JsonObject value = MobileServiceTableSerializer.Serialize(instance).AsObject();

            // Send the request
            return(DeleteAsync(value, parameters)
                   .ContinueWith(t =>
            {
                // Clear the instance ID since it's no longer associated with that
                // ID on the server (note that reflection is goodly enough to turn
                // null into the correct value for us).
                SerializableType type = SerializableType.Get(typeof(T));
                type.IdMember.SetValue(instance, 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));
        }
        /// <summary>
        /// Compile the query into a MobileServiceTableQueryDescription.
        /// </summary>
        /// <returns>The compiled OData query.</returns>
        internal MobileServiceTableQueryDescription Compile()
        {
            // Compile the query from the underlying IQueryable's expression
            // tree
            MobileServiceTableQueryDescription compiledQuery = MobileServiceTableQueryTranslator.Translate(this.Query.Expression);

            // Forward along the request for the total count
            compiledQuery.IncludeTotalCount = this.RequestTotalCount;

            // Forward along the user-defined query string parameters
            compiledQuery.Parameters = this.Parameters;

            // Associate the current table with the compiled query
            if (string.IsNullOrEmpty(compiledQuery.TableName))
            {
                SerializableType type = SerializableType.Get(
                    compiledQuery.ProjectionArgumentType ?? typeof(T));
                compiledQuery.TableName = type.TableName;
            }

            return(compiledQuery);
        }
Example #6
0
        /// <summary>
        /// Gets a reference to a table and its data operations.
        /// </summary>
        /// <typeparam name="T">
        /// The type of the elements in the table.  This implies the name of
        /// the table will either be the type's name or the value of the
        /// DataTableAttribute applied to the type.
        /// </typeparam>
        /// <returns>A reference to the table.</returns>
        public IMobileServiceTable <T> GetTable <T>()
        {
            SerializableType type = SerializableType.Get(typeof(T));

            return(new MobileServiceTable <T>(type.TableName, this));
        }
Example #7
0
        /// <summary>
        /// Deserialize a JSON value into an instance.
        /// </summary>
        /// <param name="value">The JSON value.</param>
        /// <param name="instance">The instance to deserialize into.</param>
        /// <param name="ignoreCustomSerialization">
        /// A value to indicate whether or not custom serialization should be
        /// ignored if the instance implements
        /// ICustomMobileServiceTableSerialization.  This flag is used by
        /// implementations of ICustomMobileServiceTableSerialization that want
        /// to invoke the default serialization behavior.
        /// </param>
        public static void Deserialize(JToken value, object instance, bool ignoreCustomSerialization)
        {
            if (value == null)
            {
                throw new ArgumentNullException("value");
            }
            else if (instance == null)
            {
                throw new ArgumentNullException("instance");
            }

            // If the instance implements
            // ICustomMobileServiceTableSerialization, allow it to handle its
            // own deserialization.
            if (!ignoreCustomSerialization)
            {
                ICustomMobileServiceTableSerialization custom = instance as ICustomMobileServiceTableSerialization;
                if (custom != null)
                {
                    custom.Deserialize(value);
                    return;
                }
            }

            // Get the Mobile Services specific type info
            SerializableType type = SerializableType.Get(instance.GetType());

            // Get the object to deserialize
            JObject obj = value.AsObject();

            if (obj == null)
            {
                throw new ArgumentException(
                          string.Format(
                              CultureInfo.InvariantCulture,
                              Resources.MobileServiceTableSerializer_Deserialize_NeedObject,
                              value.Type),
                          "value");
            }

            // Create a set of required members that we can remove from as we
            // process their values from the object.  If there's anything left
            // in the set after processing all of the values, then we weren't
            // given all of our required properties.
            HashSet <SerializableMember> requiredMembers =
                new HashSet <SerializableMember>(type.Members.Values.Where(m => m.IsRequired));

            // Walk through all of the members defined in the object and
            // deserialize them into the instance one at a time
            foreach (KeyValuePair <string, JToken> assignment in obj.GetPropertyValues().OrderBy(a => type.GetMemberOrder(a.Key)))
            {
                // Look up the instance member corresponding to the JSON member
                SerializableMember member = null;
                if (type.Members.TryGetValue(assignment.Key, out member))
                {
                    // Remove the member from the required list (does nothing
                    // if it wasn't present)
                    requiredMembers.Remove(member);

                    // Convert the property value into a CLR value using either
                    // the converter or a standard simple JSON mapping.  This
                    // will throw for JSON arrays or objects.  Also note that
                    // we'll still run the value returned from the converter
                    // through the ChangeType call below to make writing
                    // converters a little easier (but it should be a no-op
                    // for most folks anyway).
                    object propertyValue = null;
                    if (member.Converter != null)
                    {
                        propertyValue = member.Converter.ConvertFromJson(assignment.Value);
                    }
                    else if (!assignment.Value.TryConvert(out propertyValue))
                    {
                        throw new ArgumentException(
                                  string.Format(
                                      CultureInfo.InvariantCulture,
                                      Resources.MobileServiceTableSerializer_Deserialize_CannotDeserializeValue,
                                      assignment.Value.ToString(),
                                      type.Type.FullName,
                                      member.MemberName),
                                  "value");
                    }

                    // Change the type of the value to the desired property
                    // type (mostly to handle things like casting issues) and
                    // set the value on the instance.
                    object convertedValue = TypeExtensions.ChangeType(propertyValue, member.Type);
                    member.SetValue(instance, convertedValue);
                }
            }

            // Ensure we were provided all of the required properties.
            if (requiredMembers.Count > 0)
            {
                throw new SerializationException(
                          string.Format(
                              CultureInfo.InvariantCulture,
                              Resources.MobileServiceTableSerializer_Deserialize_MissingRequired,
                              type.Type.FullName,
                              string.Join(", ", requiredMembers.Select(m => m.Name))));
            }
        }
Example #8
0
        /// <summary>
        /// Serialize an instance to a JSON value.
        /// </summary>
        /// <param name="instance">The instance to serialize.</param>
        /// <returns>The serialized JSON value.</returns>
        /// <param name="ignoreCustomSerialization">
        /// A value to indicate whether or not custom serialization should be
        /// ignored if the instance implements
        /// ICustomMobileServiceTableSerialization.  This flag is used by
        /// implementations of ICustomMobileServiceTableSerialization that
        /// want to invoke the default serialization behavior.
        /// </param>
        public static JToken Serialize(object instance, bool ignoreCustomSerialization)
        {
            if (instance == null)
            {
                throw new ArgumentNullException("instance");
            }

            // If the instance implements
            // ICustomMobileServiceTableSerialization, allow it to handle its
            // own serialization.
            if (!ignoreCustomSerialization)
            {
                ICustomMobileServiceTableSerialization custom = instance as ICustomMobileServiceTableSerialization;
                if (custom != null)
                {
                    return(custom.Serialize());
                }
            }

            // Get the Mobile Services specific type info
            SerializableType type = SerializableType.Get(instance.GetType());

            // Create a new JSON object to represent the instance
            JObject obj = new JObject();

            foreach (SerializableMember member in type.Members.Values.OrderBy(m => m.Order))
            {
                // Get the value to serialize
                object value = member.GetValue(instance);
                if (member.Converter != null)
                {
                    // If there's a user defined converter, we can apply that
                    // and set the value directly.
                    obj.Set(member.Name, member.Converter.ConvertToJson(value));
                }
                else if (member == type.IdMember &&
                         SerializableType.IsDefaultIdValue(value))
                {
                    // Special case the ID member so we don't write out any
                    // value if wasn't set (i.e., has a 0 or null value).  This
                    // allows us flexibility for the type of the ID column
                    // which is currently a long in SQL but could someday be a
                    // GUID in something like  a document database.  At some
                    // point we might also change the server to quietly ignore
                    // default values for the ID column on insert.
                }
                else if (!obj.TrySet(member.Name, value))
                {
                    throw new ArgumentException(
                              string.Format(
                                  CultureInfo.InvariantCulture,
                                  Resources.MobileServiceTableSerializer_Serialize_UnknownType,
                                  member.Name,
                                  member.Type.FullName,
                                  type.Type.Name),
                              "instance");
                }
            }

            return(obj);
        }