internal static ResourceType GetDeclaringTypeForProperty(ResourceType resourceType, ResourceProperty resourceProperty, ResourceType rootType = null) { while (resourceType != rootType) { if (resourceType.TryResolvePropertiesDeclaredOnThisTypeByName(resourceProperty.Name) == resourceProperty) { return(resourceType); } resourceType = resourceType.BaseType; } return(resourceType); }
/// <summary> /// Gets and validates the ResourceAssociationSet instance when given the source association end. /// </summary> /// <param name="resourceSet">Resource set of the source association end.</param> /// <param name="resourceType">Resource type of the source association end.</param> /// <param name="navigationProperty">Resource property of the source association end.</param> /// <returns>ResourceAssociationSet instance.</returns> private ResourceAssociationSet GetAndValidateResourceAssociationSet(ResourceSetWrapper resourceSet, ResourceType resourceType, ResourceProperty navigationProperty) { Debug.Assert(resourceSet != null, "resourceSet != null"); Debug.Assert(resourceType != null, "resourceType != null"); Debug.Assert(navigationProperty != null, "navigationProperty != null"); Debug.Assert(resourceType.TryResolvePropertiesDeclaredOnThisTypeByName(navigationProperty.Name) != null, "navigationProperty must be declared on resourceType."); string associationSetKey = resourceSet.Name + '_' + resourceType.FullName + '_' + navigationProperty.Name; ResourceAssociationSet associationSet; if (this.associationSets.TryGetValue(associationSetKey, out associationSet)) { return associationSet; } associationSet = this.provider.GetResourceAssociationSet(resourceSet, resourceType, navigationProperty); if (associationSet != null) { ResourceAssociationSetEnd relatedEnd = associationSet.GetRelatedResourceAssociationSetEnd(resourceSet, resourceType, navigationProperty); // If this is a two way relationship, GetResourceAssociationSet should return the same association set when called from either end. // For example, it's not valid to have the association sets {GoodCustomerSet} <-> {OrdersSet} and {BadCustomerSet} <-> {OrdersSet} // because starting from {OrderSet} we won't know which customers set to resolve to. if (relatedEnd.ResourceProperty != null) { ResourceAssociationSet reverseAssociationSet = this.provider.GetResourceAssociationSet(this.provider.ValidateResourceSet(relatedEnd.ResourceSet), relatedEnd.ResourceType, relatedEnd.ResourceProperty); if (reverseAssociationSet == null || associationSet.Name != reverseAssociationSet.Name) { throw new InvalidOperationException(Strings.ResourceAssociationSet_BidirectionalAssociationMustReturnSameResourceAssociationSetFromBothEnd); } } // Cache the association set for the reverse direction. string reverseAssociationSetKey; if (relatedEnd.ResourceProperty != null) { reverseAssociationSetKey = relatedEnd.ResourceSet.Name + '_' + relatedEnd.ResourceProperty.ResourceType.FullName + '_' + relatedEnd.ResourceProperty.Name; } else { reverseAssociationSetKey = relatedEnd.ResourceSet.Name + "_Null_" + resourceType.FullName + '_' + navigationProperty.Name; } ResourceAssociationSet conflictingAssociationSet; if (this.associationSets.TryGetValue(reverseAssociationSetKey, out conflictingAssociationSet)) { // If only one of the ends is already in the cache, we know that the provider is giving us inconsistant metadata. // Make sure that if two or more AssociationSets refer to the same AssociationType, the ends must not refer to the same EntitySet. // For CLR context, this could happen if multiple entity sets have entity types that have a common ancestor and the ancestor has a property of derived entity types. throw new InvalidOperationException(Strings.ResourceAssociationSet_MultipleAssociationSetsForTheSameAssociationTypeMustNotReferToSameEndSets(conflictingAssociationSet.Name, associationSet.Name, relatedEnd.ResourceSet.Name)); } this.associationSets.Add(reverseAssociationSetKey, associationSet); this.associationSets.Add(associationSetKey, associationSet); } return associationSet; }