524 lines
19 KiB
C#
524 lines
19 KiB
C#
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
|
|
using System;
|
|
using System.Data;
|
|
using System.Data.Common;
|
|
using System.Collections.Generic;
|
|
using System.Data.Metadata.Edm;
|
|
using System.Diagnostics;
|
|
|
|
namespace SampleEntityFrameworkProvider
|
|
{
|
|
/// <summary>
|
|
/// A set of static helpers for type metadata
|
|
/// </summary>
|
|
static class MetadataHelpers
|
|
{
|
|
#region Type Helpers
|
|
|
|
/// <summary>
|
|
/// Cast the EdmType of the given type usage to the given TEdmType
|
|
/// </summary>
|
|
/// <typeparam name="TEdmType"></typeparam>
|
|
/// <param name="typeUsage"></param>
|
|
/// <returns></returns>
|
|
internal static TEdmType GetEdmType<TEdmType>(TypeUsage typeUsage)
|
|
where TEdmType : EdmType
|
|
{
|
|
return (TEdmType)typeUsage.EdmType;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the TypeUsage of the elment if the given type is a collection type
|
|
/// </summary>
|
|
/// <param name="type"></param>
|
|
/// <returns></returns>
|
|
internal static TypeUsage GetElementTypeUsage(TypeUsage type)
|
|
{
|
|
if (MetadataHelpers.IsCollectionType(type))
|
|
{
|
|
return ((CollectionType)type.EdmType).TypeUsage;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Retrieves the properties of in the EdmType underlying the input type usage,
|
|
/// if that EdmType is a structured type (EntityType, RowType).
|
|
/// </summary>
|
|
/// <param name="typeUsage"></param>
|
|
/// <returns></returns>
|
|
internal static IList<EdmProperty> GetProperties(TypeUsage typeUsage)
|
|
{
|
|
return MetadataHelpers.GetProperties(typeUsage.EdmType);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Retrieves the properties of the given EdmType, if it is
|
|
/// a structured type (EntityType, RowType).
|
|
/// </summary>
|
|
/// <param name="edmType"></param>
|
|
/// <returns></returns>
|
|
internal static IList<EdmProperty> GetProperties(EdmType edmType)
|
|
{
|
|
switch (edmType.BuiltInTypeKind)
|
|
{
|
|
case BuiltInTypeKind.ComplexType:
|
|
return ((ComplexType)edmType).Properties;
|
|
case BuiltInTypeKind.EntityType:
|
|
return ((EntityType)edmType).Properties;
|
|
case BuiltInTypeKind.RowType:
|
|
return ((RowType)edmType).Properties;
|
|
default:
|
|
return new List<EdmProperty>();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Is the given type usage over a collection type
|
|
/// </summary>
|
|
/// <param name="typeUsage"></param>
|
|
/// <returns></returns>
|
|
internal static bool IsCollectionType(TypeUsage typeUsage)
|
|
{
|
|
return MetadataHelpers.IsCollectionType(typeUsage.EdmType);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Is the given type a collection type
|
|
/// </summary>
|
|
/// <param name="type"></param>
|
|
/// <returns></returns>
|
|
internal static bool IsCollectionType(EdmType type)
|
|
{
|
|
return (BuiltInTypeKind.CollectionType == type.BuiltInTypeKind);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Is the given type usage over a primitive type
|
|
/// </summary>
|
|
/// <param name="type"></param>
|
|
/// <returns></returns>
|
|
internal static bool IsPrimitiveType(TypeUsage type)
|
|
{
|
|
return MetadataHelpers.IsPrimitiveType(type.EdmType);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Is the given type a primitive type
|
|
/// </summary>
|
|
/// <param name="type"></param>
|
|
/// <returns></returns>
|
|
internal static bool IsPrimitiveType(EdmType type)
|
|
{
|
|
return (BuiltInTypeKind.PrimitiveType == type.BuiltInTypeKind);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Is the given type usage over a row type
|
|
/// </summary>
|
|
/// <param name="type"></param>
|
|
/// <returns></returns>
|
|
internal static bool IsRowType(TypeUsage type)
|
|
{
|
|
return MetadataHelpers.IsRowType(type.EdmType);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Is the given type usage over an entity type
|
|
/// </summary>
|
|
/// <param name="type"></param>
|
|
/// <returns></returns>
|
|
internal static bool IsEntityType(TypeUsage type)
|
|
{
|
|
return MetadataHelpers.IsEntityType(type.EdmType);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Is the given type a row type
|
|
/// </summary>
|
|
/// <param name="type"></param>
|
|
/// <returns></returns>
|
|
internal static bool IsRowType(EdmType type)
|
|
{
|
|
return (BuiltInTypeKind.RowType == type.BuiltInTypeKind);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Is the given type an Enity Type
|
|
/// </summary>
|
|
/// <param name="type"></param>
|
|
/// <returns></returns>
|
|
internal static bool IsEntityType(EdmType type)
|
|
{
|
|
return (BuiltInTypeKind.EntityType == type.BuiltInTypeKind);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the type of the given type usage if it is a primitive type
|
|
/// </summary>
|
|
/// <param name="type"></param>
|
|
/// <param name="typeKind"></param>
|
|
/// <returns></returns>
|
|
internal static bool TryGetPrimitiveTypeKind(TypeUsage type, out PrimitiveTypeKind typeKind)
|
|
{
|
|
if (type != null && type.EdmType != null && type.EdmType.BuiltInTypeKind == BuiltInTypeKind.PrimitiveType)
|
|
{
|
|
typeKind = ((PrimitiveType)type.EdmType).PrimitiveTypeKind;
|
|
return true;
|
|
}
|
|
|
|
typeKind = default(PrimitiveTypeKind);
|
|
return false;
|
|
}
|
|
|
|
internal static PrimitiveTypeKind GetPrimitiveTypeKind(TypeUsage type)
|
|
{
|
|
PrimitiveTypeKind returnValue;
|
|
if (!MetadataHelpers.TryGetPrimitiveTypeKind(type, out returnValue))
|
|
{
|
|
Debug.Assert(false, "Cannot create parameter of non-primitive type");
|
|
throw new NotSupportedException("Cannot create parameter of non-primitive type");
|
|
}
|
|
return returnValue;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the value for the metadata property with the given name
|
|
/// </summary>
|
|
/// <typeparam name="T"></typeparam>
|
|
/// <param name="item"></param>
|
|
/// <param name="propertyName"></param>
|
|
/// <returns></returns>
|
|
internal static T TryGetValueForMetadataProperty<T>(MetadataItem item, string propertyName)
|
|
{
|
|
MetadataProperty property;
|
|
if (!item.MetadataProperties.TryGetValue(propertyName, true, out property))
|
|
{
|
|
return default(T);
|
|
}
|
|
|
|
return (T)property.Value;
|
|
}
|
|
|
|
internal static bool IsPrimitiveType(TypeUsage type, PrimitiveTypeKind primitiveType)
|
|
{
|
|
PrimitiveTypeKind typeKind;
|
|
if (TryGetPrimitiveTypeKind(type, out typeKind))
|
|
{
|
|
return (typeKind == primitiveType);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
internal static bool IsSpatialType(TypeUsage type)
|
|
{
|
|
PrimitiveTypeKind spatialTypeKind;
|
|
return IsSpatialType(type, out spatialTypeKind);
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
internal static bool IsGeometricTypeKind(PrimitiveTypeKind kind)
|
|
{
|
|
return kind == PrimitiveTypeKind.Geometry || IsStrongGeometricTypeKind(kind);
|
|
}
|
|
|
|
static bool IsStrongGeometricTypeKind(PrimitiveTypeKind kind)
|
|
{
|
|
return kind >= PrimitiveTypeKind.GeometryPoint && kind <= PrimitiveTypeKind.GeometryCollection;
|
|
}
|
|
|
|
internal static bool IsGeographicTypeKind(PrimitiveTypeKind kind)
|
|
{
|
|
return kind == PrimitiveTypeKind.Geography || IsStrongGeographicTypeKind(kind);
|
|
}
|
|
|
|
static bool IsStrongGeographicTypeKind(PrimitiveTypeKind kind)
|
|
{
|
|
return kind >= PrimitiveTypeKind.GeographyPoint && kind <= PrimitiveTypeKind.GeographyCollection;
|
|
}
|
|
|
|
internal static DbType GetDbType(PrimitiveTypeKind primitiveType)
|
|
{
|
|
switch (primitiveType)
|
|
{
|
|
case PrimitiveTypeKind.Binary: return DbType.Binary;
|
|
case PrimitiveTypeKind.Boolean: return DbType.Boolean;
|
|
case PrimitiveTypeKind.Byte: return DbType.Byte;
|
|
case PrimitiveTypeKind.DateTime: return DbType.DateTime;
|
|
case PrimitiveTypeKind.Decimal: return DbType.Decimal;
|
|
case PrimitiveTypeKind.Double: return DbType.Double;
|
|
case PrimitiveTypeKind.Single: return DbType.Single;
|
|
case PrimitiveTypeKind.Guid: return DbType.Guid;
|
|
case PrimitiveTypeKind.Int16: return DbType.Int16;
|
|
case PrimitiveTypeKind.Int32: return DbType.Int32;
|
|
case PrimitiveTypeKind.Int64: return DbType.Int64;
|
|
//case PrimitiveTypeKind.Money: return DbType.Decimal;
|
|
case PrimitiveTypeKind.SByte: return DbType.SByte;
|
|
case PrimitiveTypeKind.String: return DbType.String;
|
|
//case PrimitiveTypeKind.UInt16: return DbType.UInt16;
|
|
//case PrimitiveTypeKind.UInt32: return DbType.UInt32;
|
|
//case PrimitiveTypeKind.UInt64: return DbType.UInt64;
|
|
//case PrimitiveTypeKind.Xml: return DbType.Xml;
|
|
case PrimitiveTypeKind.Geography:
|
|
case PrimitiveTypeKind.Geometry:
|
|
return DbType.Object;
|
|
default:
|
|
Debug.Fail("unknown PrimitiveTypeKind" + primitiveType.ToString());
|
|
throw new InvalidOperationException(string.Format("Unknown PrimitiveTypeKind {0}", primitiveType));
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Facet Support
|
|
internal static readonly int UnicodeStringMaxMaxLength = Int32.MaxValue / 2;
|
|
internal static readonly int AsciiStringMaxMaxLength = Int32.MaxValue;
|
|
internal static readonly int BinaryMaxMaxLength = Int32.MaxValue;
|
|
|
|
#region Facet Names
|
|
/// <summary>
|
|
/// Name of the MaxLength Facet
|
|
/// </summary>
|
|
public static readonly string MaxLengthFacetName = "MaxLength";
|
|
|
|
/// <summary>
|
|
/// Name of the Unicode Facet
|
|
/// </summary>
|
|
public static readonly string UnicodeFacetName = "Unicode";
|
|
|
|
/// <summary>
|
|
/// Name of the FixedLength Facet
|
|
/// </summary>
|
|
public static readonly string FixedLengthFacetName = "FixedLength";
|
|
|
|
/// <summary>
|
|
/// Name of the PreserveSeconds Facet
|
|
/// </summary>
|
|
public static readonly string PreserveSecondsFacetName = "PreserveSeconds";
|
|
|
|
/// <summary>
|
|
/// Name of the Precision Facet
|
|
/// </summary>
|
|
public static readonly string PrecisionFacetName = "Precision";
|
|
|
|
/// <summary>
|
|
/// Name of the Scale Facet
|
|
/// </summary>
|
|
public static readonly string ScaleFacetName = "Scale";
|
|
|
|
/// <summary>
|
|
/// Name of the DefaultValue Facet
|
|
/// </summary>
|
|
public static readonly string DefaultValueFacetName = "DefaultValue";
|
|
|
|
/// <summary>
|
|
/// Name of the Nullable Facet
|
|
/// </summary>
|
|
internal const string NullableFacetName = "Nullable";
|
|
#endregion
|
|
|
|
#region Facet Retreival Helpers
|
|
|
|
/// <summary>
|
|
/// Get the value specified on the given type usage for the given facet name.
|
|
/// If the faces does not have a value specifid or that value is null returns
|
|
/// the default value for that facet.
|
|
/// </summary>
|
|
/// <typeparam name="T"></typeparam>
|
|
/// <param name="type"></param>
|
|
/// <param name="facetName"></param>
|
|
/// <returns></returns>
|
|
/// <summary>
|
|
/// Get the value specified on the given type usage for the given facet name.
|
|
/// If the faces does not have a value specifid or that value is null returns
|
|
/// the default value for that facet.
|
|
/// </summary>
|
|
/// <typeparam name="T"></typeparam>
|
|
/// <param name="type"></param>
|
|
/// <param name="facetName"></param>
|
|
/// <returns></returns>
|
|
internal static T GetFacetValueOrDefault<T>(TypeUsage type, string facetName, T defaultValue)
|
|
{
|
|
//Get the value for the facet, if any
|
|
Facet facet;
|
|
if (type.Facets.TryGetValue(facetName, false, out facet) && facet.Value != null && !facet.IsUnbounded)
|
|
{
|
|
return (T)facet.Value;
|
|
}
|
|
else
|
|
{
|
|
return defaultValue;
|
|
}
|
|
}
|
|
|
|
internal static bool IsFacetValueConstant(TypeUsage type, string facetName)
|
|
{
|
|
return MetadataHelpers.GetFacet(((PrimitiveType)type.EdmType).FacetDescriptions, facetName).IsConstant;
|
|
}
|
|
|
|
private static FacetDescription GetFacet(IEnumerable<FacetDescription> facetCollection, string facetName)
|
|
{
|
|
foreach (FacetDescription facetDescription in facetCollection)
|
|
{
|
|
if (facetDescription.FacetName == facetName)
|
|
{
|
|
return facetDescription;
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Given a facet name and an EdmType, tries to get that facet's description.
|
|
/// </summary>
|
|
/// <param name="edmType"></param>
|
|
/// <param name="facetName"></param>
|
|
/// <param name="facetDescription"></param>
|
|
/// <returns></returns>
|
|
internal static bool TryGetTypeFacetDescriptionByName(EdmType edmType, string facetName, out FacetDescription facetDescription)
|
|
{
|
|
facetDescription = null;
|
|
if (MetadataHelpers.IsPrimitiveType(edmType))
|
|
{
|
|
PrimitiveType primitiveType = (PrimitiveType)edmType;
|
|
foreach (FacetDescription fd in primitiveType.FacetDescriptions)
|
|
{
|
|
if (facetName.Equals(fd.FacetName, StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
facetDescription = fd;
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
internal static bool IsNullable(TypeUsage type)
|
|
{
|
|
Facet nullableFacet;
|
|
if (type.Facets.TryGetValue(NullableFacetName, false, out nullableFacet))
|
|
{
|
|
return (bool)nullableFacet.Value;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
internal static bool TryGetMaxLength(TypeUsage type, out int maxLength)
|
|
{
|
|
if (!IsPrimitiveType(type, PrimitiveTypeKind.String) &&
|
|
!IsPrimitiveType(type, PrimitiveTypeKind.Binary))
|
|
{
|
|
maxLength = 0;
|
|
return false;
|
|
}
|
|
|
|
// Binary and String FixedLength facets share the same name
|
|
return TryGetIntFacetValue(type, MaxLengthFacetName, out maxLength);
|
|
}
|
|
|
|
internal static bool TryGetIntFacetValue(TypeUsage type, string facetName, out int intValue)
|
|
{
|
|
intValue = 0;
|
|
Facet intFacet;
|
|
|
|
if (type.Facets.TryGetValue(facetName, false, out intFacet) && intFacet.Value != null && !intFacet.IsUnbounded)
|
|
{
|
|
intValue = (int)intFacet.Value;
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
internal static bool TryGetIsFixedLength(TypeUsage type, out bool isFixedLength)
|
|
{
|
|
if (!IsPrimitiveType(type, PrimitiveTypeKind.String) &&
|
|
!IsPrimitiveType(type, PrimitiveTypeKind.Binary))
|
|
{
|
|
isFixedLength = false;
|
|
return false;
|
|
}
|
|
|
|
// Binary and String MaxLength facets share the same name
|
|
return TryGetBooleanFacetValue(type, FixedLengthFacetName, out isFixedLength);
|
|
}
|
|
|
|
internal static bool TryGetBooleanFacetValue(TypeUsage type, string facetName, out bool boolValue)
|
|
{
|
|
boolValue = false;
|
|
Facet boolFacet;
|
|
if (type.Facets.TryGetValue(facetName, false, out boolFacet) && boolFacet.Value != null)
|
|
{
|
|
boolValue = (bool)boolFacet.Value;
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
internal static bool TryGetIsUnicode(TypeUsage type, out bool isUnicode)
|
|
{
|
|
if (!IsPrimitiveType(type, PrimitiveTypeKind.String))
|
|
{
|
|
isUnicode = false;
|
|
return false;
|
|
}
|
|
|
|
return TryGetBooleanFacetValue(type, UnicodeFacetName, out isUnicode);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
internal static bool IsCanonicalFunction(EdmFunction function)
|
|
{
|
|
return (function.NamespaceName == "Edm");
|
|
}
|
|
|
|
internal static bool IsStoreFunction(EdmFunction function)
|
|
{
|
|
return !IsCanonicalFunction(function);
|
|
}
|
|
|
|
// Returns ParameterDirection corresponding to given ParameterMode
|
|
internal static ParameterDirection ParameterModeToParameterDirection(ParameterMode mode)
|
|
{
|
|
switch (mode)
|
|
{
|
|
case ParameterMode.In:
|
|
return ParameterDirection.Input;
|
|
|
|
case ParameterMode.InOut:
|
|
return ParameterDirection.InputOutput;
|
|
|
|
case ParameterMode.Out:
|
|
return ParameterDirection.Output;
|
|
|
|
case ParameterMode.ReturnValue:
|
|
return ParameterDirection.ReturnValue;
|
|
|
|
default:
|
|
Debug.Fail("unrecognized mode " + mode.ToString());
|
|
return default(ParameterDirection);
|
|
}
|
|
}
|
|
}
|
|
}
|