예제 #1
0
        /// <summary>
        /// Resets the given resource
        /// </summary>
        /// <param name="resource">The resource to reset</param>
        /// <returns>The reset resource</returns>
        public virtual object ResetResource(object resource)
        {
            ExceptionUtilities.CheckArgumentNotNull(resource, "resource");

            var token = UpdatableToken.AssertIsToken(resource, "resource");
            resource = token.Resource;

            // create a new token
            token = new UpdatableToken(resource);

            var instance = resource as ResourceInstance;
            ExceptionUtilities.CheckObjectNotNull(instance, "Resource was not a resource instance. Type was '{0}'", resource.GetType());

            var resourceType = this.metadataHelper.ResourceTypes.Single(t => t.FullName == instance.ResourceTypeName);
            foreach (ResourceProperty p in resourceType.GetAllPropertiesLazily())
            {
                var property = p;
                if ((property.Kind & (ResourcePropertyKind.Key | ResourcePropertyKind.ResourceReference | ResourcePropertyKind.ResourceSetReference)) == 0)
                {
                    // TODO: initialize to defaults?
                    this.pendingChanges.Add(() => instance.Remove(property.Name));
                }
            }

            // remove all dynamic properties
            // the ToList is so we can modify the collection inside the loop
            foreach (string key in instance.Keys.Except(resourceType.GetAllPropertiesLazily().Select(p => p.Name)).ToList())
            {
                var propertyName = key;
                this.pendingChanges.Add(() => instance.Remove(propertyName));
            }

            this.InitializeCollectionProperties(resourceType, instance, token, p => p.Kind == ResourcePropertyKind.Collection);

            return token;
        }
예제 #2
0
        /// <summary>
        /// Creates a resource in the given set with the given type
        /// </summary>
        /// <param name="containerName">The given set name</param>
        /// <param name="fullTypeName">The given type name</param>
        /// <returns>The resource created</returns>
        public virtual object CreateResource(string containerName, string fullTypeName)
        {
            ExceptionUtilities.CheckArgumentNotNull(fullTypeName, "fullTypeName");

            ResourceType type = this.metadataHelper.ResourceTypes.SingleOrDefault(t => t.FullName == fullTypeName);
            ExceptionUtilities.CheckObjectNotNull(type, "Could not find type with name '{0}'", fullTypeName);
            ExceptionUtilities.ThrowDataServiceExceptionIfFalse(!type.IsAbstract, 400, "Cannot create resource because type '{0}' is abstract.", type.FullName);

            ResourceInstance instance;
            if (type.ResourceTypeKind == ResourceTypeKind.ComplexType)
            {
                ExceptionUtilities.Assert(containerName == null, "Container name must be null for complex types. Value was '{0}'", containerName);

                if (type.InstanceType == typeof(ResourceInstance))
                {
                    instance = new ResourceInstance(type);
                }
                else
                {
                    ConstructorInfo constructor = type.InstanceType.GetConstructor(new[] { typeof(ResourceType) });
                    ExceptionUtilities.CheckObjectNotNull(constructor, "Could not find constructor for complex type '{0}'", type.InstanceType);
                    instance = (ResourceInstance)constructor.Invoke(new object[] { type });
                }
            }
            else
            {
                ExceptionUtilities.CheckArgumentNotNull(containerName, "containerName");
                ResourceSet set = this.GetResourceSet(containerName);
                ExceptionUtilities.CheckObjectNotNull(set, "Could not find resource set with name '{0}'", containerName);

                ExceptionUtilities.Assert(set.ResourceType == type || this.GetDerivedTypesInternal(set.ResourceType).Contains(type), "An entity of type '{0}' cannot be added to set '{1}'", fullTypeName, containerName);

                if (type.InstanceType == typeof(ResourceInstance))
                {
                    instance = new ResourceInstance(type, set);
                }
                else
                {
                    ConstructorInfo constructor = type.InstanceType.GetConstructor(new[] { typeof(ResourceType), typeof(ResourceSet) });
                    ExceptionUtilities.CheckObjectNotNull(constructor, "Could not find constructor for entity type '{0}'", type.InstanceType);
                    instance = (ResourceInstance)constructor.Invoke(new object[] { type, set });
                }

                // TODO: better message
                ExceptionUtilities.ThrowDataServiceExceptionIfFalse(!this.ResourceSetsStorage[set.Name].Any(e => this.AreKeysEqual(e, instance)), 500, "Duplicate key");

                this.pendingChanges.Add(() => this.ResourceSetsStorage[set.Name].Add(instance));
            }

            var token = new UpdatableToken(instance);

            // foreach property marked as being server generated
            foreach (ResourceProperty property in type.GetAllPropertiesLazily())
            {
                string propertyName = property.Name;
                object generatedValue;
                if (this.TryGetStoreGeneratedValue(containerName, fullTypeName, propertyName, out generatedValue))
                {
                    token.PendingPropertyUpdates[propertyName] = generatedValue;
                    this.pendingChanges.Add(() => instance[propertyName] = generatedValue);
                }
            }

            this.InitializeCollectionProperties(type, instance, token, p => p.Kind == ResourcePropertyKind.ResourceSetReference || p.Kind == ResourcePropertyKind.Collection);

            return token;
        }
예제 #3
0
        /// <summary>
        /// Gets the value of the given property
        /// </summary>
        /// <param name="targetResource">The resource to get the property value from</param>
        /// <param name="propertyName">The property name</param>
        /// <returns>The value of the property</returns>
        public virtual object GetValue(object targetResource, string propertyName)
        {
            ExceptionUtilities.CheckArgumentNotNull(targetResource, "targetResource");
            ExceptionUtilities.CheckArgumentNotNull(propertyName, "propertyName");

            // resolve the token, and return a pending value if there is one
            // NOTE: this code is specifically to handle cases of mapped complex-type values, because the product does not cache the
            // value returned by CreateResource so we need to take into account any pending updates, or we risk returning stale data
            var token = UpdatableToken.AssertIsToken(targetResource, "targetResource");
            if (token.PendingPropertyUpdates.ContainsKey(propertyName))
            {
                return token.PendingPropertyUpdates[propertyName];
            }

            targetResource = token.Resource;
            var instance = targetResource as ResourceInstance;
            ExceptionUtilities.CheckObjectNotNull(instance, "Target resource was not a resource instance. Type was '{0}'", targetResource.GetType());

            var resourceType = this.metadataHelper.ResourceTypes.Single(t => t.FullName == instance.ResourceTypeName);
            var property = resourceType.GetAllPropertiesLazily().SingleOrDefault(p => p.Name == propertyName);
            if (property != null)
            {
                ExceptionUtilities.Assert(!property.Kind.HasFlag(ResourcePropertyKind.Stream), "GetValue called on stream property '{0}'", property.Name);
            }

            object value = null;
            
            // Check for strongly typed properties
            var type = targetResource.GetType();
            PropertyInfo propertyInfo = type.GetProperty(propertyName);
            if (propertyInfo != null)
            {
                value = propertyInfo.GetValue(targetResource, null);
            }
            else
            {
                object propertyValue;
                if (instance.TryGetValue(propertyName, out propertyValue))
                {
                    value = propertyValue;
                }
            }

            var valueInstance = value as ResourceInstance;
            if (valueInstance != null)
            {
                ExceptionUtilities.Assert(!valueInstance.IsEntityType, "GetValue should never be called for reference properties. Type was '{0}', property was '{1}'", resourceType.FullName, propertyName);
                value = new UpdatableToken(valueInstance);
            }

            return value;
        }
예제 #4
0
 private void InitializeCollectionProperties(ResourceType type, ResourceInstance instance, UpdatableToken token, Func<ResourceProperty, bool> filter)
 {
     foreach (ResourceProperty property in type.GetAllPropertiesLazily().Where(filter))
     {
         string propertyName = property.Name;
         Type collectionType = this.GetCollectionPropertyType(type.FullName, propertyName);
         if (collectionType != null)
         {
             var newCollection = Activator.CreateInstance(collectionType);
             token.PendingPropertyUpdates[propertyName] = newCollection;
             this.pendingChanges.Add(() => instance[propertyName] = newCollection);
         }
     }
 }