//--------------------------------------------------------------------- // // Copyright (c) Microsoft Corporation. All rights reserved. // // // @owner [....] // @backupOwner [....] //--------------------------------------------------------------------- namespace System.Data.Metadata.Edm { using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Text; using System.Xml; using System.Xml.XPath; /// /// Helper Class for EDM Metadata - this class contains all the helper methods /// which only accesses public methods/properties. The other partial class contains all /// helper methods which just uses internal methods/properties. The reason why we /// did this for allowing view gen to happen at compile time - all the helper /// methods that view gen or mapping uses are in this class. Rest of the /// methods are in this class /// internal static partial class Helper { #region Fields internal static readonly EdmMember[] EmptyArrayEdmProperty = new EdmMember[0]; #endregion #region Methods /// /// The method wraps the GetAttribute method on XPathNavigator. /// The problem with using the method directly is that the /// Get Attribute method does not differentiate the absence of an attribute and /// having an attribute with Empty string value. In both cases the value returned is an empty string. /// So in case of optional attributes, it becomes hard to distinguish the case whether the /// xml contains the attribute with empty string or doesn't contain the attribute /// This method will return null if the attribute is not present and otherwise will return the /// attribute value. /// /// /// name of the attribute /// static internal string GetAttributeValue(XPathNavigator nav, string attributeName) { //Clone the navigator so that there wont be any sideeffects on the passed in Navigator nav = nav.Clone(); string attributeValue = null; if (nav.MoveToAttribute(attributeName, string.Empty)) { attributeValue = nav.Value; } return attributeValue; } /// /// The method returns typed attribute value of the specified xml attribute. /// The method does not do any specific casting but uses the methods on XPathNavigator. /// /// /// /// /// internal static object GetTypedAttributeValue(XPathNavigator nav, string attributeName, Type clrType) { //Clone the navigator so that there wont be any sideeffects on the passed in Navigator nav = nav.Clone(); object attributeValue = null; if (nav.MoveToAttribute(attributeName, string.Empty)) { attributeValue = nav.ValueAs(clrType); } return attributeValue; } /// /// Searches for Facet Description with the name specified. /// /// Collection of facet description /// name of the facet /// internal static FacetDescription GetFacet(IEnumerable facetCollection, string facetName) { foreach (FacetDescription facetDescription in facetCollection) { if (facetDescription.FacetName == facetName) { return facetDescription; } } return null; } // requires: firstType is not null // effects: Returns true iff firstType is assignable from secondType internal static bool IsAssignableFrom(EdmType firstType, EdmType secondType) { Debug.Assert(firstType != null, "firstType should not be not null"); if (secondType == null) { return false; } return firstType.Equals(secondType) || IsSubtypeOf(secondType, firstType); } // requires: firstType is not null // effects: if otherType is among the base types, return true, // otherwise returns false. // when othertype is same as the current type, return false. internal static bool IsSubtypeOf(EdmType firstType, EdmType secondType) { Debug.Assert(firstType != null, "firstType should not be not null"); if (secondType == null) { return false; } // walk up my type hierarchy list for (EdmType t = firstType.BaseType; t != null; t = t.BaseType) { if (t == secondType) return true; } return false; } internal static IList GetAllStructuralMembers(EdmType edmType) { switch (edmType.BuiltInTypeKind) { case BuiltInTypeKind.AssociationType: return ((AssociationType)edmType).AssociationEndMembers; case BuiltInTypeKind.ComplexType: return ((ComplexType)edmType).Properties; case BuiltInTypeKind.EntityType: return ((EntityType)edmType).Properties; case BuiltInTypeKind.RowType: return ((RowType)edmType).Properties; default: return EmptyArrayEdmProperty; } } internal static AssociationEndMember GetEndThatShouldBeMappedToKey(AssociationType associationType) { //For 1:* and 1:0..1 associations, the end other than 1 i.e. either * or 0..1 ends need to be //mapped to key columns if (associationType.AssociationEndMembers.Any( it => it.RelationshipMultiplicity.Equals(RelationshipMultiplicity.One))) { { return associationType.AssociationEndMembers.SingleOrDefault(it => ((it.RelationshipMultiplicity.Equals(RelationshipMultiplicity.Many)) || (it.RelationshipMultiplicity.Equals(RelationshipMultiplicity.ZeroOrOne)))); } } //For 0..1:* associations, * end must be mapped to key. else if (associationType.AssociationEndMembers.Any(it => (it.RelationshipMultiplicity.Equals(RelationshipMultiplicity.ZeroOrOne)))) { { return associationType.AssociationEndMembers.SingleOrDefault(it => ((it.RelationshipMultiplicity.Equals(RelationshipMultiplicity.Many)))); } } return null; } /// /// Creates a single comma delimited string given a list of strings /// /// /// internal static String GetCommaDelimitedString(IEnumerable stringList) { Debug.Assert(stringList != null , "Expecting a non null list"); StringBuilder sb = new StringBuilder(); bool first = true; foreach (string part in stringList) { if (!first) { sb.Append(", "); } else { first = false; } sb.Append(part); } return sb.ToString(); } // effects: concatenates all given enumerations internal static IEnumerable Concat(params IEnumerable[] sources) { foreach (IEnumerable source in sources) { if (null != source) { foreach (T element in source) { yield return element; } } } } internal static void DisposeXmlReaders(IEnumerable xmlReaders) { Debug.Assert(xmlReaders != null); foreach (XmlReader xmlReader in xmlReaders) { ((IDisposable)xmlReader).Dispose(); } } #region IsXXXType Methods internal static bool IsStructuralType(EdmType type) { return (IsComplexType(type) || IsEntityType(type) || IsRelationshipType(type) || IsRowType(type)); } internal static bool IsCollectionType(GlobalItem item) { return (BuiltInTypeKind.CollectionType == item.BuiltInTypeKind); } internal static bool IsEntityType(EdmType type) { return (BuiltInTypeKind.EntityType == type.BuiltInTypeKind); } internal static bool IsComplexType(EdmType type) { return (BuiltInTypeKind.ComplexType == type.BuiltInTypeKind); } internal static bool IsPrimitiveType(EdmType type) { return (BuiltInTypeKind.PrimitiveType == type.BuiltInTypeKind); } internal static bool IsRefType(GlobalItem item) { return (BuiltInTypeKind.RefType == item.BuiltInTypeKind); } internal static bool IsRowType(GlobalItem item) { return (BuiltInTypeKind.RowType == item.BuiltInTypeKind); } internal static bool IsAssociationType(EdmType type) { return (BuiltInTypeKind.AssociationType == type.BuiltInTypeKind); } internal static bool IsRelationshipType(EdmType type) { return (BuiltInTypeKind.AssociationType == type.BuiltInTypeKind); } internal static bool IsEdmProperty(EdmMember member) { return (BuiltInTypeKind.EdmProperty == member.BuiltInTypeKind); } internal static bool IsRelationshipEndMember(EdmMember member) { return (BuiltInTypeKind.AssociationEndMember == member.BuiltInTypeKind); } internal static bool IsAssociationEndMember(EdmMember member) { return (BuiltInTypeKind.AssociationEndMember == member.BuiltInTypeKind); } internal static bool IsNavigationProperty(EdmMember member) { return (BuiltInTypeKind.NavigationProperty == member.BuiltInTypeKind); } internal static bool IsEntityTypeBase(EdmType edmType) { return Helper.IsEntityType(edmType) || Helper.IsRelationshipType(edmType); } internal static bool IsTransientType(EdmType edmType) { return Helper.IsCollectionType(edmType) || Helper.IsRefType(edmType) || Helper.IsRowType(edmType); } internal static bool IsEntitySet(EntitySetBase entitySetBase) { return BuiltInTypeKind.EntitySet == entitySetBase.BuiltInTypeKind; } internal static bool IsRelationshipSet(EntitySetBase entitySetBase) { return BuiltInTypeKind.AssociationSet == entitySetBase.BuiltInTypeKind; } internal static bool IsEntityContainer(GlobalItem item) { return BuiltInTypeKind.EntityContainer == item.BuiltInTypeKind; } internal static bool IsEdmFunction(GlobalItem item) { return BuiltInTypeKind.EdmFunction == item.BuiltInTypeKind; } internal static string GetFileNameFromUri(Uri uri) { if ( uri == null ) throw new ArgumentNullException("uri"); if ( uri.IsFile ) return uri.LocalPath; if ( uri.IsAbsoluteUri ) return uri.AbsolutePath; throw new ArgumentException(System.Data.Entity.Strings.UnacceptableUri(uri),"uri"); } internal static bool IsEnumType(EdmType edmType) { Debug.Assert(edmType != null, "edmType != null"); return BuiltInTypeKind.EnumType == edmType.BuiltInTypeKind; } internal static bool IsUnboundedFacetValue(Facet facet) { return object.ReferenceEquals(facet.Value, EdmConstants.UnboundedValue); } internal static bool IsVariableFacetValue(Facet facet) { return object.ReferenceEquals(facet.Value, EdmConstants.VariableValue); } internal static bool IsScalarType(EdmType edmType) { return IsEnumType(edmType) || IsPrimitiveType(edmType); } internal static bool IsSpatialType(PrimitiveType type) { return IsGeographicType(type) || IsGeometricType(type); } internal static bool IsSpatialType(EdmType type, out bool isGeographic) { PrimitiveType pt = type as PrimitiveType; if (pt == null) { isGeographic = false; return false; } else { isGeographic = IsGeographicType(pt); return isGeographic || IsGeometricType(pt); } } internal static bool IsGeographicType(PrimitiveType type) { return IsGeographicTypeKind(type.PrimitiveTypeKind); } internal static bool AreSameSpatialUnionType(PrimitiveType firstType, PrimitiveType secondType) { // for the purposes of type checking all geographic types should be treated as if they were the Geography union type. if (Helper.IsGeographicTypeKind(firstType.PrimitiveTypeKind) && Helper.IsGeographicTypeKind(secondType.PrimitiveTypeKind)) { return true; } // for the purposes of type checking all geometric types should be treated as if they were the Geometry union type. if (Helper.IsGeometricTypeKind(firstType.PrimitiveTypeKind) && Helper.IsGeometricTypeKind(secondType.PrimitiveTypeKind)) { return true; } return false; } internal static bool IsGeographicTypeKind(PrimitiveTypeKind kind) { return kind == PrimitiveTypeKind.Geography || IsStrongGeographicTypeKind(kind); } internal static bool IsGeometricType(PrimitiveType type) { return IsGeometricTypeKind(type.PrimitiveTypeKind); } internal static bool IsGeometricTypeKind(PrimitiveTypeKind kind) { return kind == PrimitiveTypeKind.Geometry || IsStrongGeometricTypeKind(kind); } internal static bool IsStrongSpatialTypeKind(PrimitiveTypeKind kind) { return IsStrongGeometricTypeKind(kind) || IsStrongGeographicTypeKind(kind); } static bool IsStrongGeometricTypeKind(PrimitiveTypeKind kind) { return kind >= PrimitiveTypeKind.GeometryPoint && kind <= PrimitiveTypeKind.GeometryCollection; } static bool IsStrongGeographicTypeKind(PrimitiveTypeKind kind) { return kind >= PrimitiveTypeKind.GeographyPoint && kind <= PrimitiveTypeKind.GeographyCollection; } internal static bool IsSpatialType(TypeUsage type) { return (type.EdmType.BuiltInTypeKind == BuiltInTypeKind.PrimitiveType && IsSpatialType((PrimitiveType)type.EdmType)); } internal static bool IsSpatialType(TypeUsage type, out PrimitiveTypeKind spatialType) { if (type.EdmType.BuiltInTypeKind == BuiltInTypeKind.PrimitiveType) { PrimitiveType primitiveType = (PrimitiveType)type.EdmType; if (IsGeographicTypeKind(primitiveType.PrimitiveTypeKind) || IsGeometricTypeKind(primitiveType.PrimitiveTypeKind)) { spatialType = primitiveType.PrimitiveTypeKind; return true; } } spatialType = default(PrimitiveTypeKind); return false; } #endregion /// IsXXXType region /// Performance of Enum.ToString() is slow and we use this value in building Identity internal static string ToString(System.Data.ParameterDirection value) { switch (value) { case ParameterDirection.Input: return "Input"; case ParameterDirection.Output: return "Output"; case ParameterDirection.InputOutput: return "InputOutput"; case ParameterDirection.ReturnValue: return "ReturnValue"; default: Debug.Assert(false, "which ParameterDirection.ToString() is missing?"); return value.ToString(); } } /// Performance of Enum.ToString() is slow and we use this value in building Identity internal static string ToString(System.Data.Metadata.Edm.ParameterMode value) { switch (value) { case ParameterMode.In: return EdmConstants.In; case ParameterMode.Out: return EdmConstants.Out; case ParameterMode.InOut: return EdmConstants.InOut; case ParameterMode.ReturnValue: return "ReturnValue"; default: Debug.Assert(false, "which ParameterMode.ToString() is missing?"); return value.ToString(); } } /// /// Verifies whether the given is a valid underlying type for an enumeration type. /// /// /// to verifiy. /// /// /// true if the is a valid underlying type for an enumeration type. Otherwise false. /// internal static bool IsSupportedEnumUnderlyingType(PrimitiveTypeKind typeKind) { return typeKind == PrimitiveTypeKind.Byte || typeKind == PrimitiveTypeKind.SByte || typeKind == PrimitiveTypeKind.Int16 || typeKind == PrimitiveTypeKind.Int32 || typeKind == PrimitiveTypeKind.Int64; } private static readonly Dictionary _enumUnderlyingTypeRanges = new Dictionary { { PrimitiveTypeKind.Byte, new long[] { Byte.MinValue, Byte.MaxValue } }, { PrimitiveTypeKind.SByte, new long[] { SByte.MinValue, SByte.MaxValue } }, { PrimitiveTypeKind.Int16, new long[] { Int16.MinValue, Int16.MaxValue } }, { PrimitiveTypeKind.Int32, new long[] { Int32.MinValue, Int32.MaxValue } }, { PrimitiveTypeKind.Int64, new long[] { Int64.MinValue, Int64.MaxValue } }, }; /// /// Verifies whether a value of a member of an enumeration type is in range according to underlying type of the enumeration type. /// /// Underlying type of the enumeration type. /// Value to check. /// /// true if the is in range of the . false otherwise. /// internal static bool IsEnumMemberValueInRange(PrimitiveTypeKind underlyingTypeKind, long value) { Debug.Assert(IsSupportedEnumUnderlyingType(underlyingTypeKind), "Unsupported underlying type."); return value >= _enumUnderlyingTypeRanges[underlyingTypeKind][0] && value <= _enumUnderlyingTypeRanges[underlyingTypeKind][1]; } /// /// Checks whether the is enum type and if this is the case returns its underlying type. Otherwise /// returns after casting it to PrimitiveType. /// /// Type to convert to primitive type. /// Underlying type if is enumeration type. Otherwise itself. /// This method should be called only for primitive or enumeration types. internal static PrimitiveType AsPrimitive(EdmType type) { Debug.Assert(type != null, "type != null"); Debug.Assert(IsScalarType(type), "This method must not be called for types that are neither primitive nor enums."); return Helper.IsEnumType(type) ? GetUnderlyingEdmTypeForEnumType(type) : (PrimitiveType)type; } /// /// Returns underlying EDM type of a given enum . /// /// Enum type whose underlying EDM type needs to be returned. Must not be null. /// The underlying EDM type of a given enum . internal static PrimitiveType GetUnderlyingEdmTypeForEnumType(EdmType type) { Debug.Assert(type != null, "type != null"); Debug.Assert(IsEnumType(type), "This method can be called only for enums."); return ((EnumType)type).UnderlyingType; } internal static PrimitiveType GetSpatialNormalizedPrimitiveType(EdmType type) { Debug.Assert(type != null, "type != null"); Debug.Assert(IsPrimitiveType(type), "This method can be called only for enums."); PrimitiveType primitiveType = (PrimitiveType)type; if (IsGeographicType(primitiveType) && primitiveType.PrimitiveTypeKind != PrimitiveTypeKind.Geography) { return PrimitiveType.GetEdmPrimitiveType(PrimitiveTypeKind.Geography); } else if (IsGeometricType(primitiveType) && primitiveType.PrimitiveTypeKind != PrimitiveTypeKind.Geometry) { return PrimitiveType.GetEdmPrimitiveType(PrimitiveTypeKind.Geometry); } else { return primitiveType; } } #endregion } }