private string GetIdentifierPrefix(IEdmEntityType entityType) { if (entityType.BaseEntityType() != null) { return(GetIdentifierPrefix(entityType.BaseEntityType())); } TypeMapping existingMapping; if (_typeUriMap.TryGetValue(entityType.FullName(), out existingMapping)) { return(existingMapping.IdentifierPrefix); } var keyList = entityType.DeclaredKey.ToList(); if (keyList.Count != 1) { // Ignore this entity // TODO: Log an error return(null); } var identifierPrefix = GetStringAnnotationValue(keyList.First(), AnnotationsNamespace, "IdentifierPrefix"); if (identifierPrefix == null) { // TODO: Log an error } return(identifierPrefix); }
private string GetIdentifierPrefix(IEdmEntityType entityType) { if (entityType.BaseEntityType() != null) { return GetIdentifierPrefix(entityType.BaseEntityType()); } TypeMapping existingMapping; if (_typeUriMap.TryGetValue(entityType.FullName(), out existingMapping)) { return existingMapping.IdentifierPrefix; } var keyList = entityType.DeclaredKey.ToList(); if (keyList.Count != 1) { // Ignore this entity // TODO: Log an error return null; } var identifierPrefix = GetStringAnnotationValue(keyList.First(), AnnotationsNamespace, "IdentifierPrefix"); if (identifierPrefix == null) { // TODO: Log an error } return identifierPrefix; }
protected override void ProcessEntityType(IEdmEntityType element) { base.ProcessEntityType(element); if (element.BaseEntityType() != null) { this.CheckSchemaElementReference(element.BaseEntityType()); } }
internal void WriteEntityTypeElementHeader(IEdmEntityType entityType) { this.xmlWriter.WriteStartElement(CsdlConstants.Element_EntityType); this.WriteRequiredAttribute(CsdlConstants.Attribute_Name, entityType.Name, EdmValueWriter.StringAsXml); this.WriteOptionalAttribute(CsdlConstants.Attribute_BaseType, entityType.BaseEntityType(), this.TypeDefinitionAsXml); this.WriteOptionalAttribute(CsdlConstants.Attribute_Abstract, entityType.IsAbstract, CsdlConstants.Default_Abstract, EdmValueWriter.BooleanAsXml); this.WriteOptionalAttribute(CsdlConstants.Attribute_OpenType, entityType.IsOpen, CsdlConstants.Default_OpenType, EdmValueWriter.BooleanAsXml); // HasStream value should be inherited. Only have it on base type is sufficient. bool writeHasStream = entityType.HasStream && (entityType.BaseEntityType() == null || (entityType.BaseEntityType() != null && !entityType.BaseEntityType().HasStream)); this.WriteOptionalAttribute(CsdlConstants.Attribute_HasStream, writeHasStream, CsdlConstants.Default_HasStream, EdmValueWriter.BooleanAsXml); }
/// <summary> /// Initializes the EPM annotation with EPM information from the specified type. /// </summary> /// <param name="definingEntityType">Entity type to use the EPM infromation from.</param> /// <param name="affectedEntityType">Entity type for this the EPM information is being built.</param> internal void BuildEpmForType(IEdmEntityType definingEntityType, IEdmEntityType affectedEntityType) { DebugUtils.CheckNoExternalCallers(); Debug.Assert(definingEntityType != null, "definingEntityType != null"); Debug.Assert(affectedEntityType != null, "affectedEntityType != null"); if (definingEntityType.BaseType != null) { this.BuildEpmForType(definingEntityType.BaseEntityType(), affectedEntityType); } ODataEntityPropertyMappingCollection mappingsForType = this.model.GetEntityPropertyMappings(definingEntityType); if (mappingsForType == null) { return; } foreach (EntityPropertyMappingAttribute mapping in mappingsForType) { this.epmSourceTree.Add(new EntityPropertyMappingInfo(mapping, definingEntityType, affectedEntityType)); if (definingEntityType == affectedEntityType) { if (!PropertyExistsOnType(affectedEntityType, mapping)) { this.MappingsForInheritedProperties.Add(mapping); this.MappingsForDeclaredProperties.Remove(mapping); } } } }
public void EntityType_reference_extensions() { IEdmModel edmModel = this.GetEdmModel(); IEdmEntityType derivedEntityType = edmModel.SchemaElements.OfType <IEdmEntityType>().First(c => c.BaseType != null); IEdmEntityType baseEntityType = derivedEntityType.BaseEntityType(); Assert.IsNotNull(baseEntityType, "Base entity type should not be null!"); IEdmEntityTypeReference derivedEntityTypeRef = (IEdmEntityTypeReference)derivedEntityType.ToTypeReference(); Assert.AreEqual(baseEntityType, derivedEntityTypeRef.BaseEntityType(), "EntityTypeReference.BaseEntityType()"); Assert.AreEqual(baseEntityType, derivedEntityTypeRef.BaseType(), "EntityTypeReference.BaseType()"); Assert.AreEqual(derivedEntityType.IsAbstract, derivedEntityTypeRef.IsAbstract(), "StructuralTypeReference.IsAbstract()"); Assert.AreEqual(derivedEntityType.IsOpen, derivedEntityTypeRef.IsOpen(), "StructuralTypeReference.IsOpen()"); Assert.AreEqual(derivedEntityType.DeclaredStructuralProperties().Count(), derivedEntityTypeRef.DeclaredStructuralProperties().Count(), "StructuralTypeReference.DeclaredStructuralProperties()"); Assert.AreEqual(derivedEntityType.StructuralProperties().Count(), derivedEntityTypeRef.StructuralProperties().Count(), "StructuralTypeReference.StructuralProperties()"); Assert.AreEqual(derivedEntityType.DeclaredNavigationProperties().Count(), derivedEntityTypeRef.DeclaredNavigationProperties().Count(), "EntityTypeReference.DeclaredNavigationProperties()"); Assert.AreEqual(derivedEntityType.NavigationProperties().Count(), derivedEntityTypeRef.NavigationProperties().Count(), "EntityTypeReference.NavigationProperties()"); IEdmNavigationProperty result = derivedEntityTypeRef.FindNavigationProperty("_Not_Exist_"); Assert.IsNull(result, "Should not find Navigation Property {0}", "_Not_Exist_"); var navigation = derivedEntityType.NavigationProperties().First(); result = derivedEntityTypeRef.FindNavigationProperty(navigation.Name); Assert.AreEqual(navigation, result, "FindNavigationProperty({0})", navigation.Name); }
internal void WriteEntityTypeElementHeader(IEdmEntityType entityType) { this.xmlWriter.WriteStartElement("EntityType"); this.WriteRequiredAttribute <string>("Name", entityType.Name, new Func <string, string>(EdmValueWriter.StringAsXml)); this.WriteOptionalAttribute <IEdmEntityType>("BaseType", entityType.BaseEntityType(), new Func <IEdmEntityType, string>(this.TypeDefinitionAsXml)); this.WriteOptionalAttribute <bool>("Abstract", entityType.IsAbstract, false, new Func <bool, string>(EdmValueWriter.BooleanAsXml)); this.WriteOptionalAttribute <bool>("OpenType", entityType.IsOpen, false, new Func <bool, string>(EdmValueWriter.BooleanAsXml)); }
internal void WriteEntityTypeElementHeader(IEdmEntityType entityType) { this.xmlWriter.WriteStartElement(CsdlConstants.Element_EntityType); this.WriteRequiredAttribute(CsdlConstants.Attribute_Name, entityType.Name, EdmValueWriter.StringAsXml); this.WriteOptionalAttribute(CsdlConstants.Attribute_BaseType, entityType.BaseEntityType(), this.TypeDefinitionAsXml); this.WriteOptionalAttribute(CsdlConstants.Attribute_Abstract, entityType.IsAbstract, CsdlConstants.Default_Abstract, EdmValueWriter.BooleanAsXml); this.WriteOptionalAttribute(CsdlConstants.Attribute_OpenType, entityType.IsOpen, CsdlConstants.Default_OpenType, EdmValueWriter.BooleanAsXml); }
public static IEdmEntityType AssertHasEntityType(this IEdmModel model, Type mappedEntityClrType, Type mappedEntityBaseType) { IEdmEntityType entity = AssertHasEntityType(model, mappedEntityClrType); IEdmEntityType baseEntity = AssertHasEntityType(model, mappedEntityBaseType); Assert.Equal(baseEntity, entity.BaseEntityType()); return(entity); }
private static void PropertiesThreadFunction(object o) { IEdmModel model = (IEdmModel)o; int index = 0; foreach (IEdmSchemaElement element in model.SchemaElements) { IEdmEntityType entityType = element as IEdmEntityType; if (entityType != null) { IEdmEntityType baseType = entityType.BaseEntityType(); if (BaseTypes[index] == null) { BaseTypes[index] = baseType; } if (BaseTypes[index] != baseType) { BaseTypes[index] = BadBaseType; } IEnumerable <IEdmProperty> declaredProperties = entityType.DeclaredProperties; if (Properties[index] == null) { Properties[index] = declaredProperties; } if (Properties[index] != declaredProperties) { Properties[index] = BadProperties; } int innerIndex = 0; foreach (IEdmProperty property in declaredProperties) { IEdmTypeReference propertyType = property.Type; int effectiveIndex = (index * 10) + innerIndex; if (PropertyTypes[effectiveIndex] == null) { PropertyTypes[effectiveIndex] = propertyType; } if (PropertyTypes[effectiveIndex] != propertyType) { PropertyTypes[effectiveIndex] = BadTypeReference; } innerIndex++; } index++; } } }
private static IEnumerable <IEdmEntityType> GetTypeHierarchy(IEdmEntityType entityType) { IEdmEntityType current = entityType; while (current != null) { yield return(current); current = current.BaseEntityType(); } }
internal static bool HasEntityPropertyMappings(this IEdmModel model, IEdmEntityType entityType) { for (IEdmEntityType type = entityType; type != null; type = type.BaseEntityType()) { if (model.GetEntityPropertyMappings(type) != null) { return(true); } } return(false); }
/// <summary> /// Find all base types for a given <see cref="IEdmEntityType"/> /// </summary> /// <param name="entityType">The given entity type.</param> /// <returns>All base types or null.</returns> public static IEnumerable <IEdmEntityType> FindAllBaseTypes(this IEdmEntityType entityType) { if (entityType == null) { yield return(null); } IEdmEntityType current = entityType.BaseEntityType(); while (current != null) { yield return(current); current = current.BaseEntityType(); } }
private static ODataEntityPropertyMappingCache EnsureEpmCacheInternal(IEdmModel model, IEdmEntityType entityType, int maxMappingCount, out bool cacheModified) { cacheModified = false; if (entityType == null) { return(null); } IEdmEntityType type = entityType.BaseEntityType(); ODataEntityPropertyMappingCache baseCache = null; if (type != null) { baseCache = EnsureEpmCacheInternal(model, type, maxMappingCount, out cacheModified); } ODataEntityPropertyMappingCache epmCache = model.GetEpmCache(entityType); if (model.HasOwnOrInheritedEpm(entityType)) { ODataEntityPropertyMappingCollection entityPropertyMappings = model.GetEntityPropertyMappings(entityType); if (!(((epmCache == null) || cacheModified) || epmCache.IsDirty(entityPropertyMappings))) { return(epmCache); } cacheModified = true; int totalMappingCount = ValidationUtils.ValidateTotalEntityPropertyMappingCount(baseCache, entityPropertyMappings, maxMappingCount); epmCache = new ODataEntityPropertyMappingCache(entityPropertyMappings, model, totalMappingCount); try { epmCache.BuildEpmForType(entityType, entityType); epmCache.EpmSourceTree.Validate(entityType); model.SetAnnotationValue <ODataEntityPropertyMappingCache>(entityType, epmCache); return(epmCache); } catch { model.RemoveEpmCache(entityType); throw; } } if (epmCache != null) { cacheModified = true; model.RemoveEpmCache(entityType); } return(epmCache); }
// returns -1 if type does not derive from baseType and a positive number representing the distance // between them if it does. private static int IsDerivedTypeOf(IEdmEntityType type, IEdmEntityType baseType) { int distance = 0; while (type != null) { if (baseType == type) { return(distance); } type = type.BaseEntityType(); distance++; } return(-1); }
private static ODataEntityPropertyMappingCache EnsureEpmCacheInternal(IEdmModel model, IEdmEntityType entityType, int maxMappingCount, out bool cacheModified) { cacheModified = false; if (entityType == null) { return null; } IEdmEntityType type = entityType.BaseEntityType(); ODataEntityPropertyMappingCache baseCache = null; if (type != null) { baseCache = EnsureEpmCacheInternal(model, type, maxMappingCount, out cacheModified); } ODataEntityPropertyMappingCache epmCache = model.GetEpmCache(entityType); if (model.HasOwnOrInheritedEpm(entityType)) { ODataEntityPropertyMappingCollection entityPropertyMappings = model.GetEntityPropertyMappings(entityType); if (!(((epmCache == null) || cacheModified) || epmCache.IsDirty(entityPropertyMappings))) { return epmCache; } cacheModified = true; int totalMappingCount = ValidationUtils.ValidateTotalEntityPropertyMappingCount(baseCache, entityPropertyMappings, maxMappingCount); epmCache = new ODataEntityPropertyMappingCache(entityPropertyMappings, model, totalMappingCount); try { epmCache.BuildEpmForType(entityType, entityType); epmCache.EpmSourceTree.Validate(entityType); model.SetAnnotationValue<ODataEntityPropertyMappingCache>(entityType, epmCache); return epmCache; } catch { model.RemoveEpmCache(entityType); throw; } } if (epmCache != null) { cacheModified = true; model.RemoveEpmCache(entityType); } return epmCache; }
private static bool TryGetAlternateKeys(this IEdmModel model, IEdmEntityType entityType, IEdmTerm term, out IEnumerable <IDictionary <string, IEdmPathExpression> > alternateKeys) { IEdmEntityType checkingType = entityType; while (checkingType != null) { IEnumerable <IDictionary <string, IEdmPathExpression> > declaredAlternateKeys = GetDeclaredAlternateKeysForType(model, checkingType, term); if (declaredAlternateKeys != null) { alternateKeys = declaredAlternateKeys; return(true); } checkingType = checkingType.BaseEntityType(); } alternateKeys = null; return(false); }
internal void BuildEpmForType(IEdmEntityType definingEntityType, IEdmEntityType affectedEntityType) { if (definingEntityType.BaseType != null) { this.BuildEpmForType(definingEntityType.BaseEntityType(), affectedEntityType); } ODataEntityPropertyMappingCollection entityPropertyMappings = this.model.GetEntityPropertyMappings(definingEntityType); if (entityPropertyMappings != null) { foreach (EntityPropertyMappingAttribute attribute in entityPropertyMappings) { this.epmSourceTree.Add(new EntityPropertyMappingInfo(attribute, definingEntityType, affectedEntityType)); if ((definingEntityType == affectedEntityType) && !PropertyExistsOnType(affectedEntityType, attribute)) { this.MappingsForInheritedProperties.Add(attribute); this.MappingsForDeclaredProperties.Remove(attribute); } } } }
public void ConvertEntityType_Inheritance() { var taupoModel = new EntityModelSchema() { new EntityType("Derived") { BaseType = "Base", }, new EntityType("Base") { new MemberProperty("p1", EdmDataTypes.Int16) { IsPrimaryKey = true }, new MemberProperty("p2", EdmDataTypes.Guid), new MemberProperty("p3", EdmDataTypes.Double), }, } .ApplyDefaultNamespace("NS1") .Resolve(); IEdmModel result = this.converter.ConvertToEdmModel(taupoModel); Assert.IsNull(result.EntityContainer); Assert.AreEqual(2, result.SchemaElements.Count()); Assert.AreEqual(2, result.SchemaElements.OfType <IEdmEntityType>().Count()); IEdmEntityType convertedDerived = result.SchemaElements.OfType <IEdmEntityType>().ElementAt(0); IEdmEntityType convertedBase = result.SchemaElements.OfType <IEdmEntityType>().ElementAt(1); Assert.AreEqual("NS1.Derived", convertedDerived.FullName()); Assert.AreEqual(0, convertedDerived.DeclaredStructuralProperties().Count()); Assert.AreEqual(convertedBase, convertedDerived.BaseEntityType()); Assert.AreEqual("NS1.Base", convertedBase.FullName()); Assert.AreEqual(3, convertedBase.DeclaredStructuralProperties().Count()); Assert.AreEqual(1, convertedDerived.Key().Count()); Assert.AreEqual(1, convertedBase.DeclaredKey.Count()); Assert.AreEqual(convertedBase.DeclaredKey.First(), convertedDerived.Key().First()); }
// Performs overload resolution between a set of matching bindable actions. OData protocol ensures that there // cannot be multiple bindable actions with same name and different sets of non-bindable paramters. // The resolution logic is simple and is dependant only on the binding parameter and chooses the action that is defined // closest to the binding parameter in the inheritance hierarchy. private static IEdmFunctionImport FindBest(string actionIdentifier, IEnumerable <IEdmFunctionImport> bindableActions, IEdmEntityType bindingParameterType, bool isCollection) { if (bindingParameterType == null) { return(null); } List <IEdmFunctionImport> actionsBoundToThisType = new List <IEdmFunctionImport>(); foreach (IEdmFunctionImport action in bindableActions) { IEdmType actionParameterType = action.Parameters.First().Type.Definition; if (isCollection) { actionParameterType = ((IEdmCollectionType)actionParameterType).ElementType.Definition; } if (actionParameterType == bindingParameterType) { actionsBoundToThisType.Add(action); } } if (actionsBoundToThisType.Count > 1) { throw Error.Argument( "actionIdentifier", SRResources.ActionResolutionFailed, actionIdentifier, String.Join(", ", actionsBoundToThisType.Select(match => match.Container.FullName() + "." + match.Name))); } else if (actionsBoundToThisType.Count == 1) { return(actionsBoundToThisType[0]); } else { return(FindBest(actionIdentifier, bindableActions, bindingParameterType.BaseEntityType(), isCollection)); } }
private EntityType ConvertToTaupoEntityType(IEdmEntityType edmEntityType) { var taupoEntityType = new EntityType(edmEntityType.Namespace, edmEntityType.Name) { IsAbstract = edmEntityType.IsAbstract, IsOpen = edmEntityType.IsOpen, }; if (edmEntityType.BaseType != null) { taupoEntityType.BaseType = new EntityTypeReference(edmEntityType.BaseEntityType().Namespace, edmEntityType.BaseEntityType().Name); } foreach (var edmProperty in edmEntityType.DeclaredStructuralProperties()) { var taupoProperty = this.ConvertToTaupoProperty(edmProperty); taupoProperty.IsPrimaryKey = edmEntityType.Key().Contains(edmProperty); taupoEntityType.Add(taupoProperty); } this.ConvertAnnotationsIntoTaupo(edmEntityType, taupoEntityType); return(taupoEntityType); }
/// <summary> /// Asserts that a given entity type is derived from the specified base entity type. /// </summary> /// <param name="derivedType">The derived entity type.</param> /// <param name="baseType">The base entity type.</param> public static void AssertEntityTypeIsDerivedFrom(IEdmEntityType derivedType, IEdmEntityType baseType) { ExceptionUtilities.CheckArgumentNotNull(derivedType, "derivedType"); ExceptionUtilities.CheckArgumentNotNull(baseType, "baseType"); if (derivedType == baseType) { return; } var entityType = derivedType.BaseEntityType(); while (entityType != null) { if (entityType == baseType) { return; } entityType = entityType.BaseEntityType(); } ExceptionUtilities.Assert(false, "Expected entity type " + derivedType.FullName() + " to be derived from " + baseType.FullName()); }
/// <summary> /// Gets an enumerable containing the given type and all of its base/ancestor types. /// </summary> /// <param name="entityType">The starting entity type. Will be included in the returned enumeration.</param> /// <returns>An enumerable containing the given type and all of its base/ancestor types.</returns> private static IEnumerable <IEdmEntityType> GetBaseTypesAndSelf(IEdmEntityType entityType) { for (IEdmEntityType currentType = entityType; currentType != null; currentType = currentType.BaseEntityType()) { yield return(currentType); } }
private static bool HasOwnOrInheritedEpm(this IEdmModel model, IEdmEntityType entityType) { if (entityType == null) { return false; } if (model.GetAnnotationValue<ODataEntityPropertyMappingCollection>(entityType) != null) { return true; } LoadEpmAnnotations(model, entityType); return ((model.GetAnnotationValue<ODataEntityPropertyMappingCollection>(entityType) != null) || model.HasOwnOrInheritedEpm(entityType.BaseEntityType())); }
private static bool HasOwnOrInheritedEpm(this IEdmModel model, IEdmEntityType entityType) { if (entityType == null) { return(false); } if (model.GetAnnotationValue <ODataEntityPropertyMappingCollection>(entityType) != null) { return(true); } LoadEpmAnnotations(model, entityType); return((model.GetAnnotationValue <ODataEntityPropertyMappingCollection>(entityType) != null) || model.HasOwnOrInheritedEpm(entityType.BaseEntityType())); }
// returns -1 if type does not derive from baseType and a positive number representing the distance // between them if it does. private static int IsDerivedTypeOf(IEdmEntityType type, IEdmEntityType baseType) { int distance = 0; while (type != null) { if (baseType == type) { return distance; } type = type.BaseEntityType(); distance++; } return -1; }
/// <summary> /// Checks whether the <paramref name="entityType"/> has EPM defined for it (either directly /// on the type or on one of the base types). /// </summary> /// <param name="model">The <see cref="IEdmModel"/> containing the annotation.</param> /// <param name="entityType">The <see cref="IEdmEntityType"/> to check.</param> /// <returns>true if the <paramref name="entityType"/> has EPM defined; otherwise false.</returns> private static bool HasOwnOrInheritedEpm(this IEdmModel model, IEdmEntityType entityType) { if (entityType == null) { return false; } Debug.Assert(model != null, "model != null"); if (model.GetAnnotationValue<ODataEntityPropertyMappingCollection>(entityType) != null) { return true; } // If we don't have an in-memory annotation, try to load the serializable EPM annotations LoadEpmAnnotations(model, entityType); if (model.GetAnnotationValue<ODataEntityPropertyMappingCollection>(entityType) != null) { return true; } return model.HasOwnOrInheritedEpm(entityType.BaseEntityType()); }
private EntityType ConvertToTaupoEntityType(IEdmEntityType edmEntityType) { var taupoEntityType = new EntityType(edmEntityType.Namespace, edmEntityType.Name) { IsAbstract = edmEntityType.IsAbstract, IsOpen = edmEntityType.IsOpen, }; if (edmEntityType.BaseType != null) { taupoEntityType.BaseType = new EntityTypeReference(edmEntityType.BaseEntityType().Namespace, edmEntityType.BaseEntityType().Name); } foreach (var edmProperty in edmEntityType.DeclaredStructuralProperties()) { var taupoProperty = this.ConvertToTaupoProperty(edmProperty); taupoProperty.IsPrimaryKey = edmEntityType.Key().Contains(edmProperty); taupoEntityType.Add(taupoProperty); } this.ConvertAnnotationsIntoTaupo(edmEntityType, taupoEntityType); return taupoEntityType; }
// Performs overload resolution between a set of matching bindable actions. OData protocol ensures that there // cannot be multiple bindable actions with same name and different sets of non-bindable paramters. // The resolution logic is simple and is dependant only on the binding parameter and chooses the action that is defined // closest to the binding parameter in the inheritance hierarchy. private static IEdmFunctionImport FindBest(string actionIdentifier, IEnumerable<IEdmFunctionImport> bindableActions, IEdmEntityType bindingParameterType, bool isCollection) { if (bindingParameterType == null) { return null; } List<IEdmFunctionImport> actionsBoundToThisType = new List<IEdmFunctionImport>(); foreach (IEdmFunctionImport action in bindableActions) { IEdmType actionParameterType = action.Parameters.First().Type.Definition; if (isCollection) { actionParameterType = ((IEdmCollectionType)actionParameterType).ElementType.Definition; } if (actionParameterType == bindingParameterType) { actionsBoundToThisType.Add(action); } } if (actionsBoundToThisType.Count > 1) { throw Error.Argument( "actionIdentifier", SRResources.ActionResolutionFailed, actionIdentifier, String.Join(", ", actionsBoundToThisType.Select(match => match.Container.FullName() + "." + match.Name))); } else if (actionsBoundToThisType.Count == 1) { return actionsBoundToThisType[0]; } else { return FindBest(actionIdentifier, bindableActions, bindingParameterType.BaseEntityType(), isCollection); } }
/// <summary> /// Ensures that an up-to-date EPM cache exists for the specified <paramref name="entityType"/>. /// If no cache exists, a new one will be created based on the public mappings (if any). /// If the public mappings have changed (and the cache is thus dirty), the method re-constructs the cache. /// If all public mappings have been removed, the method also removes the EPM cache. /// </summary> /// <param name="model">IEdmModel instance containing the annotations.</param> /// <param name="entityType">IEdmEntityType instance for which to ensure the EPM cache.</param> /// <param name="maxMappingCount">The maximum allowed number of entity property mappings /// for a given entity type (on the type itself and all its base types).</param> /// <param name="cacheModified">true if the cache was modified; otherwise false.</param> /// <returns>An instance of <see cref="ODataEntityPropertyMappingCache"/>, if there are any EPM mappings for the given entity type, otherwise returns null.</returns> private static ODataEntityPropertyMappingCache EnsureEpmCacheInternal( IEdmModel model, IEdmEntityType entityType, int maxMappingCount, out bool cacheModified) { cacheModified = false; if (entityType == null) { return null; } // Make sure the EPM of the base type is initialized. IEdmEntityType baseEntityType = entityType.BaseEntityType(); ODataEntityPropertyMappingCache baseCache = null; if (baseEntityType != null) { baseCache = EnsureEpmCacheInternal(model, baseEntityType, maxMappingCount, out cacheModified); } ODataEntityPropertyMappingCache epmCache = model.GetEpmCache(entityType); if (model.HasOwnOrInheritedEpm(entityType)) { ODataEntityPropertyMappingCollection mappings = model.GetEntityPropertyMappings(entityType); bool needToBuildCache = epmCache == null || cacheModified || epmCache.IsDirty(mappings); if (needToBuildCache) { cacheModified = true; int totalMappingCount = ValidationUtils.ValidateTotalEntityPropertyMappingCount(baseCache, mappings, maxMappingCount); epmCache = new ODataEntityPropertyMappingCache(mappings, model, totalMappingCount); // Build the EPM tree and validate it try { epmCache.BuildEpmForType(entityType, entityType); epmCache.EpmSourceTree.Validate(entityType); epmCache.EpmTargetTree.Validate(); // We set the annotation here, so if anything fails during // building of the cache the annotation will not even be set so // not leaving the type in an inconsistent state. model.SetAnnotationValue(entityType, epmCache); } catch { // Remove an existing EPM cache if it is dirty to make sure we don't leave // stale caches in case building of the cache fails. // NOTE: we do this in the catch block to ensure that we always make a single // SetAnnotation call to either set or clear the existing annotation // since the SetAnnotation method is thread-safe model.RemoveEpmCache(entityType); throw; } } } else { if (epmCache != null) { // remove an existing EPM cache if the mappings have been removed from the type cacheModified = true; model.RemoveEpmCache(entityType); } } return epmCache; }
/// <summary> /// /// </summary> /// <param name="context"></param> public bool AppliesToAction(ODataControllerActionContext context) { if (context == null) { throw new ArgumentNullException(nameof(context)); } // use the cached Debug.Assert(context.Singleton != null); Debug.Assert(context.Action != null); ActionModel action = context.Action; string singletonName = context.Singleton.Name; string prefix = context.Prefix; IEdmModel model = context.Model; string actionMethodName = action.ActionMethod.Name; if (IsSupportedActionName(actionMethodName, singletonName)) { ODataPathTemplate template = new ODataPathTemplate(new SingletonSegmentTemplate(context.Singleton)); action.AddSelector(context.Prefix, context.Model, template); // processed return(true); } // type cast // Get{SingletonName}From{EntityTypeName} or GetFrom{EntityTypeName} int index = actionMethodName.IndexOf("From", StringComparison.Ordinal); if (index == -1) { return(false); } string actionPrefix = actionMethodName.Substring(0, index); if (IsSupportedActionName(actionPrefix, singletonName)) { IEdmEntityType entityType = context.Singleton.EntityType(); string castTypeName = actionMethodName.Substring(index + 4); // Shall we cast to base type and the type itself? I think yes. IEdmEntityType baseType = entityType; while (baseType != null) { if (baseType.Name == castTypeName) { ODataPathTemplate template = new ODataPathTemplate(new SingletonSegmentTemplate(context.Singleton), new CastSegmentTemplate(baseType)); action.AddSelector(context.Prefix, context.Model, template); return(true); } baseType = baseType.BaseEntityType(); } // shall we cast to derived type IEdmEntityType castType = model.FindAllDerivedTypes(entityType).OfType <IEdmEntityType>().FirstOrDefault(c => c.Name == castTypeName); if (castType != null) { ODataPathTemplate template = new ODataPathTemplate(new SingletonSegmentTemplate(context.Singleton), new CastSegmentTemplate(castType)); action.AddSelector(context.Prefix, context.Model, template); return(true); } } return(false); }