/// <summary>Creates a new instance of the <see cref="T:Microsoft.OData.Service.Providers.ResourceAssociationSetEnd" /> class.</summary> /// <param name="resourceSet">The resource set to which the <see cref="T:Microsoft.OData.Service.Providers.ResourceAssociationSetEnd" /> end belongs.</param> /// <param name="resourceType">The resource type to which the <see cref="T:Microsoft.OData.Service.Providers.ResourceAssociationSetEnd" /> end belongs.</param> /// <param name="resourceProperty">The resource property that returns the <see cref="T:Microsoft.OData.Service.Providers.ResourceAssociationSetEnd" /> end.</param> public ResourceAssociationSetEnd(ResourceSet resourceSet, ResourceType resourceType, ResourceProperty resourceProperty) { WebUtil.CheckArgumentNull(resourceSet, "resourceSet"); WebUtil.CheckArgumentNull(resourceType, "resourceType"); if (resourceProperty != null && (resourceType.TryResolvePropertyName(resourceProperty.Name) == null || resourceProperty.TypeKind != ResourceTypeKind.EntityType)) { throw new ArgumentException(Strings.ResourceAssociationSetEnd_ResourcePropertyMustBeNavigationPropertyOnResourceType); } if (!resourceSet.ResourceType.IsAssignableFrom(resourceType) && !resourceType.IsAssignableFrom(resourceSet.ResourceType)) { throw new ArgumentException(Strings.ResourceAssociationSetEnd_ResourceTypeMustBeAssignableToResourceSet); } this.resourceSet = resourceSet; this.resourceType = resourceType; // Note that for the TargetEnd, resourceProperty can be null. this.resourceProperty = resourceProperty; }
/// <summary> /// Verify that the property referred by the existing node and the new segment are both open properties or declared properties /// and if the existing node is an expand node, make sure that the target resource types are the same. /// </summary> /// <param name="existingNode">Existing node with the same property name.</param> /// <param name="property">ResourceProperty instance for the property refered by the new segment.</param> /// <param name="targetResourceType">TargetResourceType for the new segment.</param> /// <param name="expandNode">true if the existingNode is an expand node.</param> private static void VerifyPropertyMismatchAndExpandSelectMismatchScenario(ProjectionNode existingNode, ResourceProperty property, ResourceType targetResourceType, bool expandNode) { Debug.Assert( existingNode.TargetResourceType.IsAssignableFrom(targetResourceType) || targetResourceType.IsAssignableFrom(existingNode.TargetResourceType), "This method must be called if the existingNode and targetResourceType are in the same inheritance chain"); Debug.Assert(!expandNode || existingNode is ExpandedProjectionNode, "If expandNode is true, then the existingNode must be an ExpandedProjectionNode"); if (property != existingNode.Property) { // If the property are not the same - it means one of them must be null. // This is only possible if super type is open and the property resolves to an open property. Debug.Assert(property == null || existingNode.Property == null, "One of the properties must be null, since the types belong to the same inheritance chain, and cannot have different property instance from a given property name"); // Currently we do not support scenarios where one refers to the open property on the supertype // and declared property on the sub type. throw DataServiceException.CreateBadRequestError( Strings.RequestQueryProcessor_CannotSpecifyOpenPropertyAndDeclaredPropertyAtTheSameTime( existingNode.PropertyName, property == null ? targetResourceType.FullName : existingNode.TargetResourceType.FullName, property == null ? existingNode.TargetResourceType.FullName : targetResourceType.FullName)); } if (!ResourceType.CompareReferences(targetResourceType, existingNode.TargetResourceType) && expandNode) { // If expand and select are specified on the same property within a given type // hierarchy, currently we enforce that they must be specified on the same type throw DataServiceException.CreateBadRequestError( Strings.RequestQueryProcessor_SelectAndExpandCannotBeSpecifiedTogether(existingNode.PropertyName)); } }
/// <summary> /// Whether the given property can be applied to the existing node. /// </summary> /// <param name="existingNode">Existing node with the same property name.</param> /// <param name="property">ResourceProperty instance for the property refered by the new segment.</param> /// <param name="targetResourceType">TargetResourceType for the new segment.</param> /// <returns>true if the given property can be applied to the existing node, otherwise returns false.</returns> /// <remarks>In case this function returns true, it might modify the TargetResourceType property of the existing node.</remarks> private static bool ApplyPropertyToExistingNode(ProjectionNode existingNode, ResourceProperty property, ResourceType targetResourceType) { Debug.Assert(existingNode != null, "existingNode != null"); Debug.Assert(property == null || property.Name == existingNode.PropertyName, "property == null || property.Name == existingNode.PropertyName"); // This is just quicker way of determining if declared property belongs to different sub-trees. // Since any given property can be declared once in a chain of derived types, if the property instances // are not the same, we can assume that they do not belong to the same hierarchy chain. // Even if we do not have this check, everything will just work, since we check the type assignability. if (property != null && existingNode.Property != null && property != existingNode.Property) { return false; } ExpandedProjectionNode expansionNode = existingNode as ExpandedProjectionNode; // If the target resource type of the new segment is a super type, we might // need to update the target resource type of the existing node. // Since IsAssignableFrom returns true when they are equal, it isn't require // to do anything, but if we do, it should still work. if (targetResourceType.IsAssignableFrom(existingNode.TargetResourceType)) { ExpandedProjectionNode.VerifyPropertyMismatchAndExpandSelectMismatchScenario( existingNode, property, targetResourceType, expansionNode != null); existingNode.TargetResourceType = targetResourceType; return true; } // If the existing node is already a super type, then there is nothing to do // other than validating the error scenarios. if (existingNode.TargetResourceType.IsAssignableFrom(targetResourceType)) { ExpandedProjectionNode.VerifyPropertyMismatchAndExpandSelectMismatchScenario( existingNode, property, targetResourceType, expansionNode != null); return true; } return false; }
public IEnumerable<ResourceType> GetDerivedTypes(ResourceType resourceType) { return this.resourceTypes.Where(type => resourceType.IsAssignableFrom(type) && type != resourceType); }