/// <summary> /// This method takes a type and a set of facets and returns the best mapped equivalent type /// in SQL Server, taking the store version into consideration. /// </summary> /// <param name="storeType">A TypeUsage encapsulating an EDM type and a set of facets</param> /// <returns>A TypeUsage encapsulating a store type and a set of facets</returns> public override TypeUsage GetStoreType(TypeUsage edmType) { if (edmType == null) { throw new ArgumentNullException("edmType"); } Debug.Assert(edmType.EdmType.BuiltInTypeKind == BuiltInTypeKind.PrimitiveType); if (!(edmType.EdmType is PrimitiveType primitiveType)) { throw new ArgumentException(string.Format("The underlying provider does not support the type '{0}'.", edmType)); } var facets = edmType.Facets; switch (primitiveType.PrimitiveTypeKind) { case PrimitiveTypeKind.Boolean: return(TypeUsage.CreateDefaultTypeUsage(StoreTypeNameToStorePrimitiveType["smallint_bool"])); case PrimitiveTypeKind.Int16: return(TypeUsage.CreateDefaultTypeUsage(StoreTypeNameToStorePrimitiveType["smallint"])); case PrimitiveTypeKind.Int32: return(TypeUsage.CreateDefaultTypeUsage(StoreTypeNameToStorePrimitiveType["int"])); case PrimitiveTypeKind.Int64: return(TypeUsage.CreateDefaultTypeUsage(StoreTypeNameToStorePrimitiveType["bigint"])); case PrimitiveTypeKind.Double: return(TypeUsage.CreateDefaultTypeUsage(StoreTypeNameToStorePrimitiveType["double"])); case PrimitiveTypeKind.Single: return(TypeUsage.CreateDefaultTypeUsage(StoreTypeNameToStorePrimitiveType["float"])); case PrimitiveTypeKind.Decimal: // decimal, numeric { if (!TypeHelpers.TryGetPrecision(edmType, out var precision)) { precision = 9; } if (!TypeHelpers.TryGetScale(edmType, out var scale)) { scale = 0; } return(TypeUsage.CreateDecimalTypeUsage(StoreTypeNameToStorePrimitiveType["decimal"], precision, scale)); } case PrimitiveTypeKind.Binary: // blob { var isFixedLength = null != facets[MetadataHelpers.FixedLengthFacetName].Value && (bool)facets[MetadataHelpers.FixedLengthFacetName].Value; var f = facets[MetadataHelpers.MaxLengthFacetName]; var isMaxLength = f.IsUnbounded || null == f.Value || (int)f.Value > BinaryMaxSize; var maxLength = !isMaxLength ? (int)f.Value : Int32.MinValue; TypeUsage tu; if (isFixedLength) { tu = TypeUsage.CreateBinaryTypeUsage(StoreTypeNameToStorePrimitiveType["blob"], true, maxLength); } else { if (isMaxLength) { tu = TypeUsage.CreateBinaryTypeUsage(StoreTypeNameToStorePrimitiveType["blob"], false); Debug.Assert(tu.Facets["MaxLength"].Description.IsConstant, "blob is not constant!"); } else { tu = TypeUsage.CreateBinaryTypeUsage(StoreTypeNameToStorePrimitiveType["blob"], false, maxLength); } } return(tu); } case PrimitiveTypeKind.String: // char, varchar, text blob { var isUnicode = null == facets[MetadataHelpers.UnicodeFacetName].Value || (bool)facets[MetadataHelpers.UnicodeFacetName].Value; var isFixedLength = null != facets[MetadataHelpers.FixedLengthFacetName].Value && (bool)facets[MetadataHelpers.FixedLengthFacetName].Value; var f = facets[MetadataHelpers.MaxLengthFacetName]; // maxlen is true if facet value is unbounded, the value is bigger than the limited string sizes *or* the facet // value is null. this is needed since functions still have maxlength facet value as null var isMaxLength = f.IsUnbounded || null == f.Value || (int)f.Value > (isUnicode ? UnicodeVarcharMaxSize : AsciiVarcharMaxSize); var maxLength = !isMaxLength ? (int)f.Value : Int32.MinValue; TypeUsage tu; if (isUnicode) { if (isFixedLength) { tu = TypeUsage.CreateStringTypeUsage(StoreTypeNameToStorePrimitiveType["char"], true, true, maxLength); } else { if (isMaxLength) { tu = TypeUsage.CreateStringTypeUsage(StoreTypeNameToStorePrimitiveType["clob"], true, false); } else { tu = TypeUsage.CreateStringTypeUsage(StoreTypeNameToStorePrimitiveType["varchar"], true, false, maxLength); } } } else { if (isFixedLength) { tu = TypeUsage.CreateStringTypeUsage(StoreTypeNameToStorePrimitiveType["char"], false, true, maxLength); } else { if (isMaxLength) { tu = TypeUsage.CreateStringTypeUsage(StoreTypeNameToStorePrimitiveType["clob"], false, false); } else { tu = TypeUsage.CreateStringTypeUsage(StoreTypeNameToStorePrimitiveType["varchar"], false, false, maxLength); } } } return(tu); } case PrimitiveTypeKind.DateTime: // datetime, date { bool useTimestamp; if (TypeHelpers.TryGetPrecision(edmType, out var precision)) { if (precision == 0) { useTimestamp = false; } else { useTimestamp = true; } } else { useTimestamp = true; } return(TypeUsage.CreateDefaultTypeUsage(useTimestamp ? StoreTypeNameToStorePrimitiveType["timestamp"] : StoreTypeNameToStorePrimitiveType["date"])); } case PrimitiveTypeKind.Time: return(TypeUsage.CreateDefaultTypeUsage(StoreTypeNameToStorePrimitiveType["time"])); case PrimitiveTypeKind.Guid: return(TypeUsage.CreateDefaultTypeUsage(StoreTypeNameToStorePrimitiveType["guid"])); default: throw new NotSupportedException(string.Format("There is no store type corresponding to the EDM type '{0}' of primitive type '{1}'.", edmType, primitiveType.PrimitiveTypeKind)); } }
/// <summary> /// This method takes a type and a set of facets and returns the best mapped equivalent type /// in EDM. /// </summary> /// <param name="storeType">A TypeUsage encapsulating a store type and a set of facets</param> /// <returns>A TypeUsage encapsulating an EDM type and a set of facets</returns> public override TypeUsage GetEdmType(TypeUsage storeType) { if (storeType == null) { throw new ArgumentNullException("storeType"); } var storeTypeName = storeType.EdmType.Name.ToLowerInvariant(); if (!StoreTypeNameToEdmPrimitiveType.ContainsKey(storeTypeName)) { throw new ArgumentException(string.Format("The underlying provider does not support the type '{0}'.", storeTypeName)); } var edmPrimitiveType = base.StoreTypeNameToEdmPrimitiveType[storeTypeName]; var maxLength = 0; var isUnicode = true; var isFixedLen = false; var isUnbounded = true; PrimitiveTypeKind newPrimitiveTypeKind; switch (storeTypeName) { // for some types we just go with simple type usage with no facets case "smallint": case "int": case "bigint": case "smallint_bool": case "float": case "double": case "guid": return(TypeUsage.CreateDefaultTypeUsage(edmPrimitiveType)); case "decimal": case "numeric": if (TypeHelpers.TryGetPrecision(storeType, out var precision) && TypeHelpers.TryGetScale(storeType, out var scale)) { return(TypeUsage.CreateDecimalTypeUsage(edmPrimitiveType, precision, scale)); } else { return(TypeUsage.CreateDecimalTypeUsage(edmPrimitiveType)); } case "varchar": newPrimitiveTypeKind = PrimitiveTypeKind.String; isUnbounded = !TypeHelpers.TryGetMaxLength(storeType, out maxLength); isUnicode = true; //hardcoded isFixedLen = false; break; case "char": newPrimitiveTypeKind = PrimitiveTypeKind.String; isUnbounded = !TypeHelpers.TryGetMaxLength(storeType, out maxLength); isUnicode = true; //hardcoded isFixedLen = true; break; case "timestamp": return(TypeUsage.CreateDateTimeTypeUsage(edmPrimitiveType, null)); case "date": return(TypeUsage.CreateDateTimeTypeUsage(edmPrimitiveType, null)); case "time": return(TypeUsage.CreateTimeTypeUsage(edmPrimitiveType, null)); case "blob": newPrimitiveTypeKind = PrimitiveTypeKind.Binary; isUnbounded = true; isFixedLen = false; break; case "clob": newPrimitiveTypeKind = PrimitiveTypeKind.String; isUnbounded = true; isUnicode = true; //hardcoded isFixedLen = false; break; default: throw new NotSupportedException(string.Format("The underlying provider does not support the type '{0}'.", storeTypeName)); } Debug.Assert(newPrimitiveTypeKind == PrimitiveTypeKind.String || newPrimitiveTypeKind == PrimitiveTypeKind.Binary, "at this point only string and binary types should be present"); switch (newPrimitiveTypeKind) { case PrimitiveTypeKind.String: if (!isUnbounded) { return(TypeUsage.CreateStringTypeUsage(edmPrimitiveType, isUnicode, isFixedLen, maxLength)); } else { return(TypeUsage.CreateStringTypeUsage(edmPrimitiveType, isUnicode, isFixedLen)); } case PrimitiveTypeKind.Binary: if (!isUnbounded) { return(TypeUsage.CreateBinaryTypeUsage(edmPrimitiveType, isFixedLen, maxLength)); } else { return(TypeUsage.CreateBinaryTypeUsage(edmPrimitiveType, isFixedLen)); } default: throw new NotSupportedException(string.Format("The underlying provider does not support the type '{0}'.", storeTypeName)); } }