Ejemplo n.º 1
0
        /// <summary>
        /// Load property data from an ATOM response
        /// </summary>
        /// <param name="property">The property being loaded</param>
        /// <returns>property values as IEnumerable.</returns>
        private MaterializeAtom ReadPropertyFromAtom(ClientPropertyAnnotation property)
        {
            DataServiceContext context = (DataServiceContext)this.Source;
            bool merging = context.ApplyingChanges;

            try
            {
                context.ApplyingChanges = true;

                // store the results so that they can be there in the response body.
                Type  elementType = property.IsEntityCollection ? property.EntityCollectionItemType : property.NullablePropertyType;
                IList results     = (IList)Activator.CreateInstance(typeof(List <>).MakeGenericType(elementType));

                DataServiceQueryContinuation continuation = null;

                // elementType.ElementType has Nullable stripped away, use nestedType for materializer
                using (MaterializeAtom materializer = this.GetMaterializer(this.plan))
                {
                    Debug.Assert(materializer != null, "materializer != null -- otherwise GetMaterializer() returned null rather than empty");

                    // when SetLink to null, we cannot get materializer because have no-content response.
                    if (materializer.IsNoContentResponse() &&
                        property.GetValue(entity) != null &&
                        context.MergeOption != MergeOption.AppendOnly &&
                        context.MergeOption != MergeOption.NoTracking)
                    {
                        property.SetValue(this.entity, null, propertyName, false);
                    }
                    else
                    {
                        foreach (object child in materializer)
                        {
                            if (property.IsEntityCollection)
                            {
                                results.Add(child);
                            }
                            else if (property.IsPrimitiveOrEnumOrComplexCollection)
                            {
                                Debug.Assert(property.PropertyType.IsAssignableFrom(child.GetType()), "Created instance for storing collection items has to be compatible with the actual one.");

                                // Collection materialization rules requires to clear the collection if not null or set the property first and then add the collection items
                                object collectionInstance = property.GetValue(this.entity);
                                if (collectionInstance == null)
                                {
                                    // type of child has been resolved as per rules for collections so it is the correct type to instantiate
                                    collectionInstance = Activator.CreateInstance(child.GetType());

                                    // allowAdd is false - we need to assign instance as the new property value
                                    property.SetValue(this.entity, collectionInstance, this.propertyName, false /* allowAdd? */);
                                }
                                else
                                {
                                    // Clear existing collection
                                    property.ClearBackingICollectionInstance(collectionInstance);
                                }

                                foreach (var collectionItem in (IEnumerable)child)
                                {
                                    Debug.Assert(property.PrimitiveOrComplexCollectionItemType.IsAssignableFrom(collectionItem.GetType()), "Type of materialized collection items have to be compatible with the type of collection items in the actual collection property.");
                                    property.AddValueToBackingICollectionInstance(collectionInstance, collectionItem);
                                }

                                results.Add(collectionInstance);
                            }
                            else
                            {
                                // it is either primitive type, complex type or 1..1 navigation property so we just allow setting the value but not adding.
                                property.SetValue(this.entity, child, this.propertyName, false);
                                results.Add(child);
                            }
                        }
                    }

                    continuation = materializer.GetContinuation(null);
                }

                return(MaterializeAtom.CreateWrapper(context, results, continuation));
            }
            finally
            {
                context.ApplyingChanges = merging;
            }
        }