diff --git a/src/Microsoft.AspNetCore.OData/Abstracts/ETagActionFilterAttribute.cs b/src/Microsoft.AspNetCore.OData/Abstracts/ETagActionFilterAttribute.cs
index 025765972..c4e252903 100644
--- a/src/Microsoft.AspNetCore.OData/Abstracts/ETagActionFilterAttribute.cs
+++ b/src/Microsoft.AspNetCore.OData/Abstracts/ETagActionFilterAttribute.cs
@@ -128,7 +128,7 @@ private static IEdmEntityTypeReference GetTypeReference(IEdmModel model, IEdmEnt
return edmTypeReference.AsEntity();
}
- IEdmTypeReference reference = model.GetTypeMappingCache().GetEdmType(value.GetType(), model);
+ IEdmTypeReference reference = model.GetEdmTypeReference(value.GetType());
if (reference != null && reference.Definition.IsOrInheritsFrom(edmType))
{
return (IEdmEntityTypeReference)reference;
diff --git a/src/Microsoft.AspNetCore.OData/Common/TypeHelper.cs b/src/Microsoft.AspNetCore.OData/Common/TypeHelper.cs
index 488f24be7..b0472e8da 100644
--- a/src/Microsoft.AspNetCore.OData/Common/TypeHelper.cs
+++ b/src/Microsoft.AspNetCore.OData/Common/TypeHelper.cs
@@ -12,6 +12,7 @@
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
+using Microsoft.AspNetCore.OData.Deltas;
using Microsoft.AspNetCore.OData.Query.Wrapper;
using Microsoft.OData.ModelBuilder;
@@ -32,6 +33,29 @@ public static bool IsDynamicTypeWrapper(this Type type)
return (type != null && typeof(DynamicTypeWrapper).IsAssignableFrom(type));
}
+ public static bool IsDeltaSetWrapper(this Type type, out Type entityType) => IsTypeWrapper(typeof(DeltaSet<>), type, out entityType);
+
+ public static bool IsSelectExpandWrapper(this Type type, out Type entityType) => IsTypeWrapper(typeof(SelectExpandWrapper<>), type, out entityType);
+
+ public static bool IsComputeWrapper(this Type type, out Type entityType) => IsTypeWrapper(typeof(ComputeWrapper<>), type, out entityType);
+
+ private static bool IsTypeWrapper(Type wrappedType, Type type, out Type entityType)
+ {
+ if (type == null)
+ {
+ entityType = null;
+ return false;
+ }
+
+ if (type.IsGenericType && type.GetGenericTypeDefinition() == wrappedType)
+ {
+ entityType = type.GetGenericArguments()[0];
+ return true;
+ }
+
+ return IsTypeWrapper(wrappedType, type.BaseType, out entityType);
+ }
+
///
/// Return the collection element type.
///
diff --git a/src/Microsoft.AspNetCore.OData/Edm/DefaultODataTypeMapper.cs b/src/Microsoft.AspNetCore.OData/Edm/DefaultODataTypeMapper.cs
new file mode 100644
index 000000000..1f69b6445
--- /dev/null
+++ b/src/Microsoft.AspNetCore.OData/Edm/DefaultODataTypeMapper.cs
@@ -0,0 +1,438 @@
+//-----------------------------------------------------------------------------
+//
+// Copyright (c) .NET Foundation and Contributors. All rights reserved.
+// See License.txt in the project root for license information.
+//
+//------------------------------------------------------------------------------
+
+using System;
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+using System.Diagnostics.Contracts;
+using System.IO;
+using System.Linq;
+using System.Xml.Linq;
+using Microsoft.AspNetCore.OData.Abstracts;
+using Microsoft.AspNetCore.OData.Common;
+using Microsoft.OData.Edm;
+using Microsoft.OData.ModelBuilder;
+using Microsoft.Spatial;
+
+namespace Microsoft.AspNetCore.OData.Edm
+{
+ ///
+ /// The default implementation for .
+ ///
+ public class DefaultODataTypeMapper : IODataTypeMapper
+ {
+ ///
+ /// Creates a static instance for the Default type mapper.
+ ///
+ internal static DefaultODataTypeMapper Default = new DefaultODataTypeMapper();
+
+ #region Default_PrimitiveTypeMapping
+ ///
+ /// The default mapping between Edm primitive type and Clr primitive type.
+ /// Primitive types are cross Edm models.
+ ///
+ private static IDictionary ClrPrimitiveTypes
+ = new Dictionary();
+
+ ///
+ /// Item1 --> non-nullable
+ /// Item2 --> nullable
+ ///
+ private static IDictionary EdmPrimitiveTypes
+ = new Dictionary();
+
+ static DefaultODataTypeMapper()
+ {
+ // Do not change the order for the nullable or non-nullable. Put nullable ahead of non-nullable.
+ // By design: non-nullable will overwrite the item1.
+ BuildTypeMapping(EdmPrimitiveTypeKind.String);
+ BuildTypeMapping(EdmPrimitiveTypeKind.Boolean);
+ BuildTypeMapping(EdmPrimitiveTypeKind.Boolean);
+ BuildTypeMapping(EdmPrimitiveTypeKind.Byte);
+ BuildTypeMapping(EdmPrimitiveTypeKind.Byte);
+ BuildTypeMapping(EdmPrimitiveTypeKind.Decimal);
+ BuildTypeMapping(EdmPrimitiveTypeKind.Decimal);
+ BuildTypeMapping(EdmPrimitiveTypeKind.Double);
+ BuildTypeMapping(EdmPrimitiveTypeKind.Double);
+ BuildTypeMapping(EdmPrimitiveTypeKind.Guid);
+ BuildTypeMapping(EdmPrimitiveTypeKind.Guid);
+ BuildTypeMapping(EdmPrimitiveTypeKind.Int16);
+ BuildTypeMapping(EdmPrimitiveTypeKind.Int16);
+ BuildTypeMapping(EdmPrimitiveTypeKind.Int32);
+ BuildTypeMapping(EdmPrimitiveTypeKind.Int32);
+ BuildTypeMapping(EdmPrimitiveTypeKind.Int64);
+ BuildTypeMapping(EdmPrimitiveTypeKind.Int64);
+ BuildTypeMapping(EdmPrimitiveTypeKind.SByte);
+ BuildTypeMapping(EdmPrimitiveTypeKind.SByte);
+ BuildTypeMapping(EdmPrimitiveTypeKind.Single);
+ BuildTypeMapping(EdmPrimitiveTypeKind.Single);
+ BuildTypeMapping(EdmPrimitiveTypeKind.Binary);
+ BuildTypeMapping(EdmPrimitiveTypeKind.Stream);
+ BuildTypeMapping(EdmPrimitiveTypeKind.DateTimeOffset);
+ BuildTypeMapping(EdmPrimitiveTypeKind.DateTimeOffset);
+ BuildTypeMapping(EdmPrimitiveTypeKind.Duration);
+ BuildTypeMapping(EdmPrimitiveTypeKind.Duration);
+ BuildTypeMapping(EdmPrimitiveTypeKind.Date);
+ BuildTypeMapping(EdmPrimitiveTypeKind.Date);
+ BuildTypeMapping(EdmPrimitiveTypeKind.TimeOfDay);
+ BuildTypeMapping(EdmPrimitiveTypeKind.TimeOfDay);
+
+ BuildTypeMapping(EdmPrimitiveTypeKind.Geography);
+ BuildTypeMapping(EdmPrimitiveTypeKind.GeographyPoint);
+ BuildTypeMapping(EdmPrimitiveTypeKind.GeographyLineString);
+ BuildTypeMapping(EdmPrimitiveTypeKind.GeographyPolygon);
+ BuildTypeMapping(EdmPrimitiveTypeKind.GeographyCollection);
+ BuildTypeMapping(EdmPrimitiveTypeKind.GeographyMultiLineString);
+ BuildTypeMapping(EdmPrimitiveTypeKind.GeographyMultiPoint);
+ BuildTypeMapping(EdmPrimitiveTypeKind.GeographyMultiPolygon);
+ BuildTypeMapping(EdmPrimitiveTypeKind.Geometry);
+ BuildTypeMapping(EdmPrimitiveTypeKind.GeometryPoint);
+ BuildTypeMapping(EdmPrimitiveTypeKind.GeometryLineString);
+ BuildTypeMapping(EdmPrimitiveTypeKind.GeometryPolygon);
+ BuildTypeMapping(EdmPrimitiveTypeKind.GeometryCollection);
+ BuildTypeMapping(EdmPrimitiveTypeKind.GeometryMultiLineString);
+ BuildTypeMapping(EdmPrimitiveTypeKind.GeometryMultiPoint);
+ BuildTypeMapping(EdmPrimitiveTypeKind.GeometryMultiPolygon);
+
+ // non-standard mappings
+ BuildTypeMapping(EdmPrimitiveTypeKind.String, isStandard: false);
+ BuildTypeMapping(EdmPrimitiveTypeKind.Int32, isStandard: false);
+ BuildTypeMapping(EdmPrimitiveTypeKind.Int32, isStandard: false);
+ BuildTypeMapping(EdmPrimitiveTypeKind.Int64, isStandard: false);
+ BuildTypeMapping(EdmPrimitiveTypeKind.Int64, isStandard: false);
+ BuildTypeMapping(EdmPrimitiveTypeKind.Int64, isStandard: false);
+ BuildTypeMapping(EdmPrimitiveTypeKind.Int64, isStandard: false);
+ BuildTypeMapping(EdmPrimitiveTypeKind.String, isStandard: false);
+ BuildTypeMapping(EdmPrimitiveTypeKind.String, isStandard: false);
+ BuildTypeMapping(EdmPrimitiveTypeKind.String, isStandard: false);
+ BuildTypeMapping(EdmPrimitiveTypeKind.DateTimeOffset, isStandard: false);
+ BuildTypeMapping(EdmPrimitiveTypeKind.DateTimeOffset, isStandard: false);
+ }
+ #endregion
+
+ #region IODataTypeMapper.GetPrimitiveType
+ ///
+ /// Gets the corresponding Edm primitive type for a given type.
+ ///
+ /// The given CLR type.
+ /// Null or the Edm primitive type.
+ public virtual IEdmPrimitiveTypeReference GetPrimitiveType(Type clrType)
+ {
+ if (clrType == null)
+ {
+ return null;
+ }
+
+ return ClrPrimitiveTypes.TryGetValue(clrType, out IEdmPrimitiveTypeReference primitive) ? primitive : null;
+ }
+
+ ///
+ /// Gets the corresponding type for a given Edm primitive type .
+ ///
+ /// The given Edm primitive type.
+ /// The nullable or not.
+ /// Null or the CLR type.
+ public virtual Type GetPrimitiveType(IEdmPrimitiveType primitiveType, bool nullable)
+ {
+ if (primitiveType == null)
+ {
+ return null;
+ }
+
+ if (EdmPrimitiveTypes.TryGetValue(primitiveType, out (Type, Type) types))
+ {
+ if (nullable)
+ {
+ return types.Item2;
+ }
+ else
+ {
+ return types.Item1;
+ }
+ }
+
+ return null;
+ }
+ #endregion
+
+ ///
+ /// The cache used to hold the type mapping between and .
+ ///
+ private ConcurrentDictionary _cache = new ConcurrentDictionary();
+
+ #region ClrType -> EdmType
+ ///
+ /// Gets the corresponding Edm type for the given CLR type .
+ ///
+ /// The given Edm model.
+ /// The given CLR type.
+ /// Null or the corresponding Edm type reference.
+ public virtual IEdmTypeReference GetEdmTypeReference(IEdmModel edmModel, Type clrType)
+ {
+ if (clrType == null)
+ {
+ throw Error.ArgumentNull(nameof(clrType));
+ }
+
+ IEdmPrimitiveTypeReference primitiveType = GetPrimitiveType(clrType);
+ if (primitiveType != null)
+ {
+ return primitiveType;
+ }
+
+ if (edmModel == null)
+ {
+ throw Error.ArgumentNull(nameof(edmModel));
+ }
+
+ TypeCacheItem map = _cache.GetOrAdd(edmModel, d => new TypeCacheItem());
+
+ // Search from cache
+ if (map.TryFindEdmType(clrType, out IEdmTypeReference edmTypeRef))
+ {
+ return edmTypeRef;
+ }
+
+ // Not in the cache, let's build the Edm type reference.
+ IEdmType edmType = GetEdmType(edmModel, clrType, testCollections: true);
+ if (edmType != null)
+ {
+ bool isNullable = clrType.IsNullable();
+ edmTypeRef = edmType.ToEdmTypeReference(isNullable);
+ }
+ else
+ {
+ edmTypeRef = null;
+ }
+
+ map.AddClrToEdmMap(clrType, edmTypeRef);
+ return edmTypeRef;
+ }
+
+ private IEdmType GetEdmType(IEdmModel edmModel, Type clrType, bool testCollections)
+ {
+ Contract.Assert(edmModel != null);
+ Contract.Assert(clrType != null);
+
+ IEdmPrimitiveTypeReference primitiveType = GetPrimitiveType(clrType);
+ if (primitiveType != null)
+ {
+ return primitiveType.Definition;
+ }
+ else
+ {
+ if (testCollections)
+ {
+ Type entityType;
+ if (clrType.IsDeltaSetWrapper(out entityType))
+ {
+ IEdmType elementType = GetEdmType(edmModel, entityType, testCollections: false);
+ if (elementType != null)
+ {
+ return new EdmCollectionType(elementType.ToEdmTypeReference(entityType.IsNullable()));
+ }
+ }
+
+ Type enumerableOfT = ExtractGenericInterface(clrType, typeof(IEnumerable<>));
+ if (enumerableOfT != null)
+ {
+ Type elementClrType = enumerableOfT.GetGenericArguments()[0];
+
+ // IEnumerable> is a collection of T.
+ if (elementClrType.IsSelectExpandWrapper(out entityType))
+ {
+ elementClrType = entityType;
+ }
+
+ if (elementClrType.IsComputeWrapper(out entityType))
+ {
+ elementClrType = entityType;
+ }
+
+ IEdmType elementType = GetEdmType(edmModel, elementClrType, testCollections: false);
+ if (elementType != null)
+ {
+ return new EdmCollectionType(elementType.ToEdmTypeReference(elementClrType.IsNullable()));
+ }
+ }
+ }
+
+ Type underlyingType = TypeHelper.GetUnderlyingTypeOrSelf(clrType);
+ if (TypeHelper.IsEnum(underlyingType))
+ {
+ clrType = underlyingType;
+ }
+
+ // search for the ClrTypeAnnotation and return it if present
+ IEdmType returnType =
+ edmModel
+ .SchemaElements
+ .OfType()
+ .Select(edmType => new { EdmType = edmType, Annotation = edmModel.GetAnnotationValue(edmType) })
+ .Where(tuple => tuple.Annotation != null && tuple.Annotation.ClrType == clrType)
+ .Select(tuple => tuple.EdmType)
+ .SingleOrDefault();
+
+ // default to the EdmType with the same name as the ClrType name
+ returnType = returnType ?? edmModel.FindType(clrType.EdmFullName());
+
+ if (clrType.BaseType != null)
+ {
+ // go up the inheritance tree to see if we have a mapping defined for the base type.
+ returnType = returnType ?? GetEdmType(edmModel, clrType.BaseType, testCollections);
+ }
+
+ return returnType;
+ }
+ }
+ #endregion
+
+ #region EdmType -> ClrType
+ ///
+ /// Gets the corresponding for a given Edm type .
+ ///
+ /// The Edm model.
+ /// The Edm type.
+ /// The nullable or not.
+ /// The assembly resolver. if it's null, will use the default resolver.
+ /// Null or the CLR type.
+ public virtual Type GetClrType(IEdmModel edmModel, IEdmType edmType, bool nullable, IAssemblyResolver assembliesResolver)
+ {
+ if (edmType == null)
+ {
+ throw Error.ArgumentNull(nameof(edmType));
+ }
+
+ if (edmType.TypeKind == EdmTypeKind.Primitive)
+ {
+ return GetPrimitiveType((IEdmPrimitiveType)edmType, nullable);
+ }
+
+ if (edmModel == null)
+ {
+ throw Error.ArgumentNull(nameof(edmModel));
+ }
+
+ assembliesResolver = assembliesResolver ?? AssemblyResolverHelper.Default;
+
+ // Let's search from cache
+ TypeCacheItem map = _cache.GetOrAdd(edmModel, d => new TypeCacheItem());
+ if (map.TryFindClrType(edmType, nullable, out Type clrType))
+ {
+ return clrType;
+ }
+
+ // If not cached, find the CLR type from the model.
+ clrType = FindClrType(edmModel, edmType, assembliesResolver);
+
+ if (clrType != null && nullable && clrType.IsEnum)
+ {
+ clrType = TypeHelper.ToNullable(clrType);
+ }
+
+ map.AddEdmToClrMap(edmType, nullable, clrType);
+
+ return clrType;
+ }
+
+ ///
+ /// Finds the corresponding CLR type for a given Edm type reference.
+ ///
+ /// The Edm model.
+ /// The Edm type.
+ /// The assembly resolver.
+ /// Null or the CLR type.
+ internal static Type FindClrType(IEdmModel edmModel, IEdmType edmType, IAssemblyResolver assembliesResolver)
+ {
+ if (edmModel == null)
+ {
+ throw Error.ArgumentNull(nameof(edmModel));
+ }
+
+ if (edmType == null)
+ {
+ throw Error.ArgumentNull(nameof(edmType));
+ }
+
+ if (assembliesResolver == null)
+ {
+ throw Error.ArgumentNull(nameof(assembliesResolver));
+ }
+
+ IEdmSchemaType edmSchemaType = edmType as IEdmSchemaType;
+ if (edmSchemaType == null)
+ {
+ return null;
+ }
+
+ // by default, retrieve it from Clr type annotation.
+ ClrTypeAnnotation annotation = edmModel.GetAnnotationValue(edmSchemaType);
+ if (annotation != null)
+ {
+ return annotation.ClrType;
+ }
+
+ string typeName = edmSchemaType.FullName();
+ IEnumerable matchingTypes = GetMatchingTypes(typeName, assembliesResolver);
+
+ if (matchingTypes.Count() > 1)
+ {
+ throw Error.InvalidOperation(SRResources.MultipleMatchingClrTypesForEdmType,
+ typeName, string.Join(",", matchingTypes.Select(type => type.AssemblyQualifiedName)));
+ }
+
+ Type clrType = matchingTypes.SingleOrDefault();
+
+ // TODO: shall we save it back to model because we will cache it?
+ // I think we should not save it back to model, since we will cache it
+ // edmModel.SetAnnotationValue(edmSchemaType, new ClrTypeAnnotation(clrType));
+ return clrType;
+ }
+ #endregion
+
+ private static Type ExtractGenericInterface(Type queryType, Type interfaceType)
+ {
+ Func matchesInterface = t => t.IsGenericType && t.GetGenericTypeDefinition() == interfaceType;
+ return matchesInterface(queryType) ? queryType : queryType.GetInterfaces().FirstOrDefault(matchesInterface);
+ }
+
+ private static IEnumerable GetMatchingTypes(string edmFullName, IAssemblyResolver assembliesResolver)
+ => TypeHelper.GetLoadedTypes(assembliesResolver).Where(t => t.IsPublic && t.EdmFullName() == edmFullName);
+
+ private static void BuildTypeMapping(EdmPrimitiveTypeKind primitiveKind, bool isStandard = true)
+ {
+ Type type = typeof(T);
+ bool isNullable = type.IsNullable();
+ IEdmPrimitiveTypeReference edmPrimitiveTypeReference = EdmCoreModel.Instance.GetPrimitive(primitiveKind, isNullable);
+ ClrPrimitiveTypes[type] = edmPrimitiveTypeReference;
+
+ if (isStandard)
+ {
+ IEdmPrimitiveType primitiveType = edmPrimitiveTypeReference.PrimitiveDefinition();
+ if (isNullable)
+ {
+ // for nullable, for example System.String, we don't have non-nullable string.
+ // so, let's save it for both.
+ // And since we make the order un-changable, it means 'nullable' coming first.
+ EdmPrimitiveTypes[primitiveType] = (type, type);
+ }
+ else
+ {
+ if (EdmPrimitiveTypes.ContainsKey(primitiveType))
+ {
+ (Type _, Type edmType2) = EdmPrimitiveTypes[primitiveType];
+ EdmPrimitiveTypes[primitiveType] = (type, edmType2);
+ }
+ else
+ {
+ EdmPrimitiveTypes[primitiveType] = (type, null);
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/src/Microsoft.AspNetCore.OData/Edm/EdmClrTypeMapExtensions.cs b/src/Microsoft.AspNetCore.OData/Edm/EdmClrTypeMapExtensions.cs
index a32f83c5b..a42bf89d9 100644
--- a/src/Microsoft.AspNetCore.OData/Edm/EdmClrTypeMapExtensions.cs
+++ b/src/Microsoft.AspNetCore.OData/Edm/EdmClrTypeMapExtensions.cs
@@ -6,19 +6,12 @@
//------------------------------------------------------------------------------
using System;
-using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.Globalization;
-using System.IO;
using System.Linq;
-using System.Xml.Linq;
using Microsoft.AspNetCore.OData.Abstracts;
-using Microsoft.AspNetCore.OData.Common;
-using Microsoft.AspNetCore.OData.Deltas;
-using Microsoft.AspNetCore.OData.Query.Wrapper;
using Microsoft.OData.Edm;
using Microsoft.OData.ModelBuilder;
-using Microsoft.Spatial;
namespace Microsoft.AspNetCore.OData.Edm
{
@@ -27,134 +20,75 @@ namespace Microsoft.AspNetCore.OData.Edm
///
internal static class EdmClrTypeMapExtensions
{
- #region PrimitiveTypeMapping
///
- /// The mapping between Edm primitive type and Clr primitive type.
- ///
- private static IDictionary _builtInPrimitiveTypes = new[]
- {
- BuildTypeMapping(EdmPrimitiveTypeKind.String),
- BuildTypeMapping(EdmPrimitiveTypeKind.Boolean),
- BuildTypeMapping(EdmPrimitiveTypeKind.Boolean),
- BuildTypeMapping(EdmPrimitiveTypeKind.Byte),
- BuildTypeMapping(EdmPrimitiveTypeKind.Byte),
- BuildTypeMapping(EdmPrimitiveTypeKind.Decimal),
- BuildTypeMapping(EdmPrimitiveTypeKind.Decimal),
- BuildTypeMapping(EdmPrimitiveTypeKind.Double),
- BuildTypeMapping(EdmPrimitiveTypeKind.Double),
- BuildTypeMapping(EdmPrimitiveTypeKind.Guid),
- BuildTypeMapping(EdmPrimitiveTypeKind.Guid),
- BuildTypeMapping(EdmPrimitiveTypeKind.Int16),
- BuildTypeMapping(EdmPrimitiveTypeKind.Int16),
- BuildTypeMapping(EdmPrimitiveTypeKind.Int32),
- BuildTypeMapping(EdmPrimitiveTypeKind.Int32),
- BuildTypeMapping(EdmPrimitiveTypeKind.Int64),
- BuildTypeMapping(EdmPrimitiveTypeKind.Int64),
- BuildTypeMapping(EdmPrimitiveTypeKind.SByte),
- BuildTypeMapping(EdmPrimitiveTypeKind.SByte),
- BuildTypeMapping(EdmPrimitiveTypeKind.Single),
- BuildTypeMapping(EdmPrimitiveTypeKind.Single),
- BuildTypeMapping(EdmPrimitiveTypeKind.Binary),
- BuildTypeMapping(EdmPrimitiveTypeKind.Stream),
- BuildTypeMapping(EdmPrimitiveTypeKind.DateTimeOffset),
- BuildTypeMapping(EdmPrimitiveTypeKind.DateTimeOffset),
- BuildTypeMapping(EdmPrimitiveTypeKind.Duration),
- BuildTypeMapping(EdmPrimitiveTypeKind.Duration),
- BuildTypeMapping(EdmPrimitiveTypeKind.Date),
- BuildTypeMapping(EdmPrimitiveTypeKind.Date),
- BuildTypeMapping(EdmPrimitiveTypeKind.TimeOfDay),
- BuildTypeMapping(EdmPrimitiveTypeKind.TimeOfDay),
- BuildTypeMapping(EdmPrimitiveTypeKind.Geography),
- BuildTypeMapping(EdmPrimitiveTypeKind.GeographyPoint),
- BuildTypeMapping(EdmPrimitiveTypeKind.GeographyLineString),
- BuildTypeMapping(EdmPrimitiveTypeKind.GeographyPolygon),
- BuildTypeMapping(EdmPrimitiveTypeKind.GeographyCollection),
- BuildTypeMapping(EdmPrimitiveTypeKind.GeographyMultiLineString),
- BuildTypeMapping(EdmPrimitiveTypeKind.GeographyMultiPoint),
- BuildTypeMapping(EdmPrimitiveTypeKind.GeographyMultiPolygon),
- BuildTypeMapping(EdmPrimitiveTypeKind.Geometry),
- BuildTypeMapping(EdmPrimitiveTypeKind.GeometryPoint),
- BuildTypeMapping(EdmPrimitiveTypeKind.GeometryLineString),
- BuildTypeMapping(EdmPrimitiveTypeKind.GeometryPolygon),
- BuildTypeMapping(EdmPrimitiveTypeKind.GeometryCollection),
- BuildTypeMapping(EdmPrimitiveTypeKind.GeometryMultiLineString),
- BuildTypeMapping(EdmPrimitiveTypeKind.GeometryMultiPoint),
- BuildTypeMapping(EdmPrimitiveTypeKind.GeometryMultiPolygon),
-
- // non-standard mappings
- BuildTypeMapping(EdmPrimitiveTypeKind.String),
- BuildTypeMapping(EdmPrimitiveTypeKind.Int32),
- BuildTypeMapping(EdmPrimitiveTypeKind.Int32),
- BuildTypeMapping(EdmPrimitiveTypeKind.Int64),
- BuildTypeMapping(EdmPrimitiveTypeKind.Int64),
- BuildTypeMapping(EdmPrimitiveTypeKind.Int64),
- BuildTypeMapping(EdmPrimitiveTypeKind.Int64),
- BuildTypeMapping(EdmPrimitiveTypeKind.String),
- BuildTypeMapping(EdmPrimitiveTypeKind.String),
- BuildTypeMapping(EdmPrimitiveTypeKind.String),
- BuildTypeMapping(EdmPrimitiveTypeKind.DateTimeOffset),
- BuildTypeMapping(EdmPrimitiveTypeKind.DateTimeOffset)
- }
- .ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
-
- ///
- /// Gets the corresponding Edm primitive type for the given CLR type.
+ /// Gets the corresponding Edm primitive type for a given type.
///
/// The given CLR type.
/// Null or the Edm primitive type.
public static IEdmPrimitiveTypeReference GetEdmPrimitiveTypeReference(this Type clrType)
{
- return _builtInPrimitiveTypes.TryGetValue(clrType, out IEdmPrimitiveTypeReference primitive) ? primitive : null;
+ return DefaultODataTypeMapper.Default.GetPrimitiveType(clrType);
}
///
- /// Gets the corresponding Edm primitive type for the given CLR type.
+ /// Gets the corresponding Edm primitive type for a given type.
///
+ /// The Edm model.
/// The given CLR type.
/// Null or the Edm primitive type.
- public static IEdmPrimitiveType GetEdmPrimitiveType(this Type clrType)
+ public static IEdmPrimitiveTypeReference GetEdmPrimitiveTypeReference(this IEdmModel edmModel, Type clrType)
{
- return _builtInPrimitiveTypes.TryGetValue(clrType, out IEdmPrimitiveTypeReference primitive) ?
- (IEdmPrimitiveType)primitive.Definition : null;
+ if (edmModel == null || edmModel is EdmCoreModel)
+ {
+ return DefaultODataTypeMapper.Default.GetPrimitiveType(clrType);
+ }
+
+ return edmModel.GetTypeMapper().GetPrimitiveType(clrType);
}
///
/// Gets the corresponding CLR type for a given Edm primitive type.
///
+ /// The Edm model.
/// The given Edm primitive type.
/// Null or the CLR type.
- public static Type GetClrPrimitiveType(this IEdmPrimitiveTypeReference edmPrimitiveType)
+ public static Type GetClrPrimitiveType(this IEdmModel edmModel, IEdmPrimitiveTypeReference edmPrimitiveType)
{
- return _builtInPrimitiveTypes
- .Where(kvp => edmPrimitiveType.Definition.IsEquivalentTo(kvp.Value.Definition) && (!edmPrimitiveType.IsNullable || IsNullable(kvp.Key)))
- .Select(kvp => kvp.Key)
- .FirstOrDefault();
+ if (edmPrimitiveType == null)
+ {
+ return null;
+ }
+
+ if (edmModel == null || edmModel is EdmCoreModel)
+ {
+ return DefaultODataTypeMapper.Default.GetPrimitiveType(edmPrimitiveType.PrimitiveDefinition(), edmPrimitiveType.IsNullable);
+ }
+
+ return edmModel.GetTypeMapper().GetPrimitiveType(edmPrimitiveType);
}
///
/// Figures out if the given clr type is nonstandard edm primitive like uint, ushort, char[] etc.
/// and returns the corresponding clr type to which we map like uint => long.
///
+ /// The Edm model.
/// The potential non-standard CLR type.
/// A boolean value out to indicate whether the input CLR type is standard OData primitive type.
/// The standard CLR type or the input CLR type itself.
- public static Type IsNonstandardEdmPrimitive(this Type clrType, out bool isNonstandardEdmPrimitive)
+ public static Type IsNonstandardEdmPrimitive(this IEdmModel edmModel, Type clrType, out bool isNonstandardEdmPrimitive)
{
- IEdmPrimitiveTypeReference edmType = clrType?.GetEdmPrimitiveTypeReference();
+ IEdmPrimitiveTypeReference edmType = edmModel.GetEdmPrimitiveTypeReference(clrType);
if (edmType == null)
{
isNonstandardEdmPrimitive = false;
return clrType;
}
- Type reverseLookupClrType = edmType.GetClrPrimitiveType();
+ Type reverseLookupClrType = edmModel.GetClrPrimitiveType(edmType);
isNonstandardEdmPrimitive = (clrType != reverseLookupClrType);
return reverseLookupClrType;
}
- #endregion
-
- #region ClrType -> EdmType
///
/// Gets the Edm type reference from the CLR type.
@@ -164,14 +98,7 @@ public static Type IsNonstandardEdmPrimitive(this Type clrType, out bool isNonst
/// null or the Edm type reference.
public static IEdmTypeReference GetEdmTypeReference(this IEdmModel edmModel, Type clrType)
{
- IEdmType edmType = edmModel.GetEdmType(clrType);
- if (edmType != null)
- {
- bool isNullable = IsNullable(clrType);
- return edmType.ToEdmTypeReference(isNullable);
- }
-
- return null;
+ return edmModel.GetTypeMapper().GetEdmTypeReference(edmModel, clrType);
}
///
@@ -182,97 +109,8 @@ public static IEdmTypeReference GetEdmTypeReference(this IEdmModel edmModel, Typ
/// null or the Edm type.
public static IEdmType GetEdmType(this IEdmModel edmModel, Type clrType)
{
- if (edmModel == null)
- {
- throw Error.ArgumentNull(nameof(edmModel));
- }
-
- if (clrType == null)
- {
- throw Error.ArgumentNull(nameof(clrType));
- }
-
- return GetEdmType(edmModel, clrType, testCollections: true);
- }
-
- private static IEdmType GetEdmType(IEdmModel edmModel, Type clrType, bool testCollections)
- {
- Contract.Assert(edmModel != null);
- Contract.Assert(clrType != null);
-
- IEdmPrimitiveType primitiveType = clrType.GetEdmPrimitiveType();
- if (primitiveType != null)
- {
- return primitiveType;
- }
- else
- {
- if (testCollections)
- {
- Type entityType;
- if (IsDeltaSetWrapper(clrType, out entityType))
- {
- IEdmType elementType = GetEdmType(edmModel, entityType, testCollections: false);
- if (elementType != null)
- {
- return new EdmCollectionType(elementType.ToEdmTypeReference(IsNullable(entityType)));
- }
- }
-
- Type enumerableOfT = ExtractGenericInterface(clrType, typeof(IEnumerable<>));
- if (enumerableOfT != null)
- {
- Type elementClrType = enumerableOfT.GetGenericArguments()[0];
-
- // IEnumerable> is a collection of T.
- if (IsSelectExpandWrapper(elementClrType, out entityType))
- {
- elementClrType = entityType;
- }
-
- if (IsComputeWrapper(elementClrType, out entityType))
- {
- elementClrType = entityType;
- }
-
- IEdmType elementType = GetEdmType(edmModel, elementClrType, testCollections: false);
- if (elementType != null)
- {
- return new EdmCollectionType(elementType.ToEdmTypeReference(IsNullable(elementClrType)));
- }
- }
- }
-
- Type underlyingType = TypeHelper.GetUnderlyingTypeOrSelf(clrType);
- if (TypeHelper.IsEnum(underlyingType))
- {
- clrType = underlyingType;
- }
-
- // search for the ClrTypeAnnotation and return it if present
- IEdmType returnType =
- edmModel
- .SchemaElements
- .OfType()
- .Select(edmType => new { EdmType = edmType, Annotation = edmModel.GetAnnotationValue(edmType) })
- .Where(tuple => tuple.Annotation != null && tuple.Annotation.ClrType == clrType)
- .Select(tuple => tuple.EdmType)
- .SingleOrDefault();
-
- // default to the EdmType with the same name as the ClrType name
- returnType = returnType ?? edmModel.FindType(clrType.EdmFullName());
-
- if (clrType.BaseType != null)
- {
- // go up the inheritance tree to see if we have a mapping defined for the base type.
- returnType = returnType ?? GetEdmType(edmModel, clrType.BaseType, testCollections);
- }
- return returnType;
- }
+ return edmModel.GetEdmTypeReference(clrType)?.Definition;
}
- #endregion
-
- #region EdmType -> ClrType
///
/// Gets the corresponding CLR type for a given Edm type reference.
@@ -282,7 +120,7 @@ private static IEdmType GetEdmType(IEdmModel edmModel, Type clrType, bool testCo
/// Null or the CLR type.
public static Type GetClrType(this IEdmModel edmModel, IEdmTypeReference edmTypeReference)
{
- return edmModel.GetClrType(edmTypeReference, AssemblyResolverHelper.Default);
+ return edmModel.GetTypeMapper().GetClrType(edmModel, edmTypeReference, AssemblyResolverHelper.Default);
}
///
@@ -294,99 +132,30 @@ public static Type GetClrType(this IEdmModel edmModel, IEdmTypeReference edmType
/// Null or the CLR type.
public static Type GetClrType(this IEdmModel edmModel, IEdmTypeReference edmTypeReference, IAssemblyResolver assembliesResolver)
{
- if (edmTypeReference == null)
- {
- throw Error.ArgumentNull(nameof(edmTypeReference));
- }
-
- if (edmTypeReference.IsPrimitive())
- {
- return GetClrPrimitiveType((IEdmPrimitiveTypeReference)edmTypeReference);
- }
- else
- {
- Type clrType = edmModel.GetClrType(edmTypeReference.Definition, assembliesResolver);
- if (clrType != null && clrType.IsEnum && edmTypeReference.IsNullable)
- {
- return TypeHelper.ToNullable(clrType);
- }
-
- return clrType;
- }
+ return edmModel.GetTypeMapper().GetClrType(edmModel, edmTypeReference, assembliesResolver);
}
///
- /// Gets the corresponding CLR type for a given Edm type reference.
+ /// Gets the corresponding CLR type for a given Edm type.
///
/// The Edm model.
/// The Edm type.
/// Null or the CLR type.
- internal static Type GetClrType(this IEdmModel edmModel, IEdmType edmType)
+ public static Type GetClrType(this IEdmModel edmModel, IEdmType edmType)
{
return edmModel.GetClrType(edmType, AssemblyResolverHelper.Default);
}
///
- /// Gets the corresponding CLR type for a given Edm type reference.
+ /// Gets the corresponding CLR type for a given Edm type.
///
/// The Edm model.
/// The Edm type.
/// The assembly resolver.
/// Null or the CLR type.
- internal static Type GetClrType(this IEdmModel edmModel, IEdmType edmType, IAssemblyResolver assembliesResolver)
+ public static Type GetClrType(this IEdmModel edmModel, IEdmType edmType, IAssemblyResolver assembliesResolver)
{
- if (edmType == null)
- {
- throw Error.ArgumentNull(nameof(edmType));
- }
-
- IEdmSchemaType edmSchemaType = edmType as IEdmSchemaType;
- Contract.Assert(edmSchemaType != null);
-
- ClrTypeAnnotation annotation = edmModel.GetAnnotationValue(edmSchemaType);
- if (annotation != null)
- {
- return annotation.ClrType;
- }
-
- string typeName = edmSchemaType.FullName();
- IEnumerable matchingTypes = GetMatchingTypes(typeName, assembliesResolver);
-
- if (matchingTypes.Count() > 1)
- {
- throw Error.Argument("edmTypeReference", SRResources.MultipleMatchingClrTypesForEdmType,
- typeName, string.Join(",", matchingTypes.Select(type => type.AssemblyQualifiedName)));
- }
-
- Type type = matchingTypes.SingleOrDefault();
- if (type == null)
- {
- return null;
- }
-
- edmModel.SetAnnotationValue(edmSchemaType, new ClrTypeAnnotation(matchingTypes.SingleOrDefault()));
- return matchingTypes.SingleOrDefault();
- }
-
- #endregion
-
- internal static ClrTypeCache GetTypeMappingCache(this IEdmModel model)
- {
- Contract.Assert(model != null);
-
- ClrTypeCache typeMappingCache = model.GetAnnotationValue(model);
- if (typeMappingCache == null)
- {
- typeMappingCache = new ClrTypeCache();
- model.SetAnnotationValue(model, typeMappingCache);
- }
-
- return typeMappingCache;
- }
-
- private static IEnumerable GetMatchingTypes(string edmFullName, IAssemblyResolver assembliesResolver)
- {
- return TypeHelper.GetLoadedTypes(assembliesResolver).Where(t => t.IsPublic && t.EdmFullName() == edmFullName);
+ return edmModel.GetTypeMapper().GetClrType(edmModel, edmType, true, assembliesResolver);
}
internal static string EdmFullName(this Type clrType)
@@ -420,63 +189,5 @@ private static string MangleClrTypeName(Type type)
String.Join("_", type.GetGenericArguments().Select(t => MangleClrTypeName(t))));
}
}
-
- private static Type ExtractGenericInterface(Type queryType, Type interfaceType)
- {
- Func matchesInterface = t => t.IsGenericType && t.GetGenericTypeDefinition() == interfaceType;
- return matchesInterface(queryType) ? queryType : queryType.GetInterfaces().FirstOrDefault(matchesInterface);
- }
-
- private static bool IsDeltaSetWrapper(Type type, out Type entityType) => IsTypeWrapper(typeof(DeltaSet<>), type, out entityType);
-
- private static bool IsSelectExpandWrapper(Type type, out Type entityType) => IsTypeWrapper(typeof(SelectExpandWrapper<>), type, out entityType);
-
- internal static bool IsComputeWrapper(Type type, out Type entityType) => IsTypeWrapper(typeof(ComputeWrapper<>), type, out entityType);
-
- private static bool IsTypeWrapper(Type wrappedType, Type type, out Type entityType)
- {
- if (type == null)
- {
- entityType = null;
- return false;
- }
-
- if (type.IsGenericType && type.GetGenericTypeDefinition() == wrappedType)
- {
- entityType = type.GetGenericArguments()[0];
- return true;
- }
-
- return IsTypeWrapper(wrappedType, type.BaseType, out entityType);
- }
-
- private static KeyValuePair BuildTypeMapping(EdmPrimitiveTypeKind primitiveKind)
- => new KeyValuePair(typeof(T), EdmCoreModel.Instance.GetPrimitive(primitiveKind, IsNullable()));
-
- ///
- /// Check the input type is nullable type or not.
- ///
- /// The input CLR type.
- /// True/False.
- private static bool IsNullable(Type type)
- {
- if (type == null)
- {
- return false;
- }
-
- return !type.IsValueType || Nullable.GetUnderlyingType(type) != null;
- }
-
- ///
- /// Check the input type is nullable or not.
- ///
- /// The test CRL type.
- /// True/False.
- private static bool IsNullable()
- {
- Type type = typeof(T);
- return IsNullable(type);
- }
}
}
diff --git a/src/Microsoft.AspNetCore.OData/Edm/EdmModelAnnotationExtensions.cs b/src/Microsoft.AspNetCore.OData/Edm/EdmModelAnnotationExtensions.cs
index a6841d522..b452e079c 100644
--- a/src/Microsoft.AspNetCore.OData/Edm/EdmModelAnnotationExtensions.cs
+++ b/src/Microsoft.AspNetCore.OData/Edm/EdmModelAnnotationExtensions.cs
@@ -261,6 +261,48 @@ public static void SetModelName(this IEdmModel model, string name)
model.SetAnnotationValue(model, new ModelNameAnnotation(name));
}
+ ///
+ /// Gets the OData type mapping provider from the model.
+ ///
+ /// The Edm model.
+ /// The .
+ public static IODataTypeMapper GetTypeMapper(this IEdmModel model)
+ {
+ // use the default one if no model or no mapper registered.
+ if (model == null)
+ {
+ return DefaultODataTypeMapper.Default;
+ }
+
+ IODataTypeMapper provider = model.GetAnnotationValue(model);
+ if (provider == null)
+ {
+ return DefaultODataTypeMapper.Default;
+ }
+
+ return provider;
+ }
+
+ ///
+ /// Sets the OData type mapping provider to the model.
+ ///
+ /// The Edm model.
+ /// The given mapper.
+ public static void SetTypeMapper(this IEdmModel model, IODataTypeMapper mapper)
+ {
+ if (model == null)
+ {
+ throw Error.ArgumentNull(nameof(model));
+ }
+
+ if (mapper == null)
+ {
+ throw Error.ArgumentNull(nameof(mapper));
+ }
+
+ model.SetAnnotationValue(model, mapper);
+ }
+
///
/// Gets the declared alternate keys of the most defined entity with a declared key present.
/// Each entity type could define a set of alternate keys.
diff --git a/src/Microsoft.AspNetCore.OData/Edm/IODataTypeMapper.cs b/src/Microsoft.AspNetCore.OData/Edm/IODataTypeMapper.cs
new file mode 100644
index 000000000..089fffbc8
--- /dev/null
+++ b/src/Microsoft.AspNetCore.OData/Edm/IODataTypeMapper.cs
@@ -0,0 +1,52 @@
+//-----------------------------------------------------------------------------
+//
+// Copyright (c) .NET Foundation and Contributors. All rights reserved.
+// See License.txt in the project root for license information.
+//
+//------------------------------------------------------------------------------
+
+using System;
+using Microsoft.OData.Edm;
+using Microsoft.OData.ModelBuilder;
+
+namespace Microsoft.AspNetCore.OData.Edm
+{
+ ///
+ /// Provides the mapping between CLR type and Edm type.
+ ///
+ public interface IODataTypeMapper
+ {
+ ///
+ /// Gets the corresponding Edm primitive type for a given .
+ ///
+ /// The given CLR type.
+ /// Null or the Edm primitive type.
+ IEdmPrimitiveTypeReference GetPrimitiveType(Type clrType);
+
+ ///
+ /// Gets the corresponding for a given Edm primitive type .
+ ///
+ /// The given Edm primitive type.
+ /// The nullable or not.
+ /// Null or the CLR type.
+ Type GetPrimitiveType(IEdmPrimitiveType primitiveType, bool nullable);
+
+ ///
+ /// Gets the corresponding Edm type for the given CLR type .
+ ///
+ /// The given Edm model.
+ /// The given CLR type.
+ /// Null or the corresponding Edm type reference.
+ IEdmTypeReference GetEdmTypeReference(IEdmModel edmModel, Type clrType);
+
+ ///
+ /// Gets the corresponding for a given Edm type .
+ ///
+ /// The given Edm model.
+ /// The given Edm type.
+ /// The nullable or not.
+ /// The assembly resolver.
+ /// Null or the CLR type.
+ Type GetClrType(IEdmModel edmModel, IEdmType edmType, bool nullable, IAssemblyResolver assembliesResolver);
+ }
+}
diff --git a/src/Microsoft.AspNetCore.OData/Edm/IODataTypeMapperExtensions.cs b/src/Microsoft.AspNetCore.OData/Edm/IODataTypeMapperExtensions.cs
new file mode 100644
index 000000000..f7b638f77
--- /dev/null
+++ b/src/Microsoft.AspNetCore.OData/Edm/IODataTypeMapperExtensions.cs
@@ -0,0 +1,93 @@
+//-----------------------------------------------------------------------------
+//
+// Copyright (c) .NET Foundation and Contributors. All rights reserved.
+// See License.txt in the project root for license information.
+//
+//------------------------------------------------------------------------------
+
+using System;
+using Microsoft.AspNetCore.OData.Abstracts;
+using Microsoft.OData.Edm;
+using Microsoft.OData.ModelBuilder;
+
+namespace Microsoft.AspNetCore.OData.Edm
+{
+ ///
+ /// Extension methods for .
+ ///
+ public static class IODataTypeMapperExtensions
+ {
+ ///
+ /// Gets the corresponding for a given Edm primitive type .
+ ///
+ /// The type mapper.
+ /// The Edm primitive type reference.
+ /// Null or the CLR type.
+ public static Type GetPrimitiveType(this IODataTypeMapper mapper, IEdmPrimitiveTypeReference primitiveType)
+ {
+ if (mapper == null)
+ {
+ throw Error.ArgumentNull(nameof(mapper));
+ }
+
+ if (primitiveType == null)
+ {
+ throw Error.ArgumentNull(nameof(primitiveType));
+ }
+
+ return mapper.GetPrimitiveType(primitiveType.PrimitiveDefinition(), primitiveType.IsNullable);
+ }
+
+ ///
+ /// Gets the corresponding Edm type for the given CLR type .
+ ///
+ /// The type mapper.
+ /// The given Edm model.
+ /// The given CLR type.
+ /// Null or the corresponding Edm type.
+ public static IEdmType GetEdmType(this IODataTypeMapper mapper, IEdmModel edmModel, Type clrType)
+ {
+ if (mapper == null)
+ {
+ throw Error.ArgumentNull(nameof(mapper));
+ }
+
+ return mapper.GetEdmTypeReference(edmModel, clrType)?.Definition;
+ }
+
+ ///
+ /// Gets the corresponding for a given Edm type .
+ ///
+ /// The type mapper.
+ /// The Edm model.
+ /// The Edm type reference.
+ /// Null or the CLR type.
+ public static Type GetClrType(this IODataTypeMapper mapper, IEdmModel edmModel, IEdmTypeReference edmType)
+ {
+ return mapper.GetClrType(edmModel, edmType, AssemblyResolverHelper.Default);
+ }
+
+ ///
+ /// Gets the corresponding for a given Edm type .
+ ///
+ /// The type mapper.
+ /// The Edm model.
+ /// The Edm type.
+ /// The assembly resolver.
+ /// Null or the CLR type.
+ public static Type GetClrType(this IODataTypeMapper mapper, IEdmModel edmModel, IEdmTypeReference edmType, IAssemblyResolver assembliesResolver)
+ {
+ if (mapper == null)
+ {
+ throw Error.ArgumentNull(nameof(mapper));
+ }
+
+ if (edmType == null)
+ {
+ throw Error.ArgumentNull(nameof(edmType));
+ }
+
+ return mapper.GetClrType(edmModel, edmType.Definition, edmType.IsNullable, assembliesResolver);
+ }
+ }
+}
diff --git a/src/Microsoft.AspNetCore.OData/Edm/TypeCacheItem.cs b/src/Microsoft.AspNetCore.OData/Edm/TypeCacheItem.cs
new file mode 100644
index 000000000..ee9eb39bb
--- /dev/null
+++ b/src/Microsoft.AspNetCore.OData/Edm/TypeCacheItem.cs
@@ -0,0 +1,84 @@
+//-----------------------------------------------------------------------------
+//
+// Copyright (c) .NET Foundation and Contributors. All rights reserved.
+// See License.txt in the project root for license information.
+//
+//------------------------------------------------------------------------------
+
+using System;
+using System.Collections.Concurrent;
+using Microsoft.OData.Edm;
+
+namespace Microsoft.AspNetCore.OData.Edm
+{
+ internal class TypeCacheItem
+ {
+ #region ClrType => EdmType
+ ///
+ /// to .
+ ///
+ public ConcurrentDictionary ClrToEdmTypeCache { get; } = new ConcurrentDictionary();
+
+ public bool TryFindEdmType(Type clrType, out IEdmTypeReference edmType)
+ {
+ edmType = null;
+ if (clrType == null)
+ {
+ return false;
+ }
+
+ return ClrToEdmTypeCache.TryGetValue(clrType, out edmType);
+ }
+
+ public void AddClrToEdmMap(Type clrType, IEdmTypeReference edmType)
+ {
+ ClrToEdmTypeCache[clrType] = edmType;
+ }
+ #endregion
+
+ #region EdmType => ClrType
+ ///
+ /// to .
+ /// item1: non-nullable
+ /// item2: nullable
+ ///
+ public ConcurrentDictionary EdmToClrTypeCache { get; } = new ConcurrentDictionary();
+
+ public bool TryFindClrType(IEdmType edmType, bool isNullable, out Type clrType)
+ {
+ if (edmType == null)
+ {
+ clrType = null;
+ return false;
+ }
+
+ clrType = null;
+ if (EdmToClrTypeCache.TryGetValue(edmType, out (Type, Type) clrTypes))
+ {
+ if (isNullable)
+ {
+ clrType = clrTypes.Item2;
+ }
+ else
+ {
+ clrType = clrTypes.Item1;
+ }
+ }
+
+ return clrType != null;
+ }
+
+ public void AddEdmToClrMap(IEdmType edmType, bool isNullable, Type clrType)
+ {
+ if (isNullable)
+ {
+ EdmToClrTypeCache.AddOrUpdate(edmType, (null, clrType), (k, v) => (v.Item1, clrType));
+ }
+ else
+ {
+ EdmToClrTypeCache.AddOrUpdate(edmType, (clrType, null), (k, v) => (clrType, v.Item2));
+ }
+ }
+ #endregion
+ }
+}
diff --git a/src/Microsoft.AspNetCore.OData/Formatter/ConventionsHelpers.cs b/src/Microsoft.AspNetCore.OData/Formatter/ConventionsHelpers.cs
index 9f24c8f4c..1f3b63e6b 100644
--- a/src/Microsoft.AspNetCore.OData/Formatter/ConventionsHelpers.cs
+++ b/src/Microsoft.AspNetCore.OData/Formatter/ConventionsHelpers.cs
@@ -49,10 +49,10 @@ private static object GetKeyValue(IEdmProperty key, ResourceContext resourceCont
throw Error.InvalidOperation(SRResources.KeyValueCannotBeNull, key.Name, edmType.Definition);
}
- return ConvertValue(value, resourceContext.TimeZone);
+ return ConvertValue(value, resourceContext.TimeZone, resourceContext.EdmModel);
}
- public static object ConvertValue(object value, TimeZoneInfo timeZone)
+ public static object ConvertValue(object value, TimeZoneInfo timeZone, IEdmModel model)
{
Contract.Assert(value != null);
@@ -63,7 +63,7 @@ public static object ConvertValue(object value, TimeZoneInfo timeZone)
}
else
{
- Contract.Assert(type.GetEdmPrimitiveType() != null);
+ Contract.Assert(model.GetEdmPrimitiveTypeReference(type) != null);
value = ODataPrimitiveSerializer.ConvertUnsupportedPrimitives(value, timeZone);
}
@@ -113,7 +113,6 @@ public static string GetUriRepresentationForValue(object value, TimeZoneInfo tim
}
else
{
- Contract.Assert(type.GetEdmPrimitiveType() != null);
value = ODataPrimitiveSerializer.ConvertUnsupportedPrimitives(value, timeZone);
}
diff --git a/src/Microsoft.AspNetCore.OData/Formatter/Deserialization/CollectionDeserializationHelper.cs b/src/Microsoft.AspNetCore.OData/Formatter/Deserialization/CollectionDeserializationHelper.cs
index 9ec11ca21..a139df107 100644
--- a/src/Microsoft.AspNetCore.OData/Formatter/Deserialization/CollectionDeserializationHelper.cs
+++ b/src/Microsoft.AspNetCore.OData/Formatter/Deserialization/CollectionDeserializationHelper.cs
@@ -12,7 +12,6 @@
using System.Linq;
using System.Reflection;
using System.Runtime.Serialization;
-using Microsoft.AspNetCore.OData.Common;
using Microsoft.AspNetCore.OData.Edm;
using Microsoft.AspNetCore.OData.Formatter.Value;
using Microsoft.OData.Edm;
@@ -26,7 +25,7 @@ internal static class CollectionDeserializationHelpers
private static readonly MethodInfo _toArrayMethodInfo = typeof(Enumerable).GetMethod("ToArray");
public static void AddToCollection(this IEnumerable items, IEnumerable collection, Type elementType,
- Type resourceType, string propertyName, Type propertyType, TimeZoneInfo timeZoneInfo = null)
+ Type resourceType, string propertyName, Type propertyType, ODataDeserializerContext context = null)
{
Contract.Assert(items != null);
Contract.Assert(collection != null);
@@ -53,10 +52,10 @@ public static void AddToCollection(this IEnumerable items, IEnumerable collectio
throw new SerializationException(message);
}
- items.AddToCollectionCore(collection, elementType, list, addMethod, timeZoneInfo);
+ items.AddToCollectionCore(collection, elementType, list, addMethod, context);
}
- public static void AddToCollection(this IEnumerable items, IEnumerable collection, Type elementType, string paramName, Type paramType, TimeZoneInfo timeZoneInfo = null)
+ public static void AddToCollection(this IEnumerable items, IEnumerable collection, Type elementType, string paramName, Type paramType, ODataDeserializerContext context = null)
{
Contract.Assert(items != null);
Contract.Assert(collection != null);
@@ -76,13 +75,14 @@ public static void AddToCollection(this IEnumerable items, IEnumerable collectio
}
}
- items.AddToCollectionCore(collection, elementType, list, addMethod, timeZoneInfo);
+ items.AddToCollectionCore(collection, elementType, list, addMethod, context);
}
- private static void AddToCollectionCore(this IEnumerable items, IEnumerable collection, Type elementType, IList list, MethodInfo addMethod, TimeZoneInfo timeZoneInfo = null)
+ private static void AddToCollectionCore(this IEnumerable items, IEnumerable collection, Type elementType, IList list, MethodInfo addMethod, ODataDeserializerContext context = null)
{
+ IEdmModel model = context?.Model;
bool isNonstandardEdmPrimitiveCollection;
- elementType.IsNonstandardEdmPrimitive(out isNonstandardEdmPrimitiveCollection);
+ model.IsNonstandardEdmPrimitive(elementType, out isNonstandardEdmPrimitiveCollection);
foreach (object item in items)
{
@@ -91,7 +91,7 @@ private static void AddToCollectionCore(this IEnumerable items, IEnumerable coll
if (isNonstandardEdmPrimitiveCollection && element != null)
{
// convert non-standard edm primitives if required.
- element = EdmPrimitiveHelper.ConvertPrimitiveValue(element, elementType, timeZoneInfo);
+ element = EdmPrimitiveHelper.ConvertPrimitiveValue(element, elementType, context?.TimeZone);
}
if (list != null)
diff --git a/src/Microsoft.AspNetCore.OData/Formatter/Deserialization/DeserializationHelper.cs b/src/Microsoft.AspNetCore.OData/Formatter/Deserialization/DeserializationHelper.cs
index 10cea2303..a020f9152 100644
--- a/src/Microsoft.AspNetCore.OData/Formatter/Deserialization/DeserializationHelper.cs
+++ b/src/Microsoft.AspNetCore.OData/Formatter/Deserialization/DeserializationHelper.cs
@@ -103,15 +103,15 @@ internal static void SetDeclaredProperty(object resource, EdmTypeKind propertyKi
}
}
- internal static void SetCollectionProperty(object resource, IEdmProperty edmProperty, object value, string propertyName, TimeZoneInfo timeZoneInfo = null)
+ internal static void SetCollectionProperty(object resource, IEdmProperty edmProperty, object value, string propertyName, ODataDeserializerContext context = null)
{
Contract.Assert(edmProperty != null);
- SetCollectionProperty(resource, propertyName, edmProperty.Type.AsCollection(), value, clearCollection: false, timeZoneInfo: timeZoneInfo);
+ SetCollectionProperty(resource, propertyName, edmProperty.Type.AsCollection(), value, clearCollection: false, context: context);
}
internal static void SetCollectionProperty(object resource, string propertyName,
- IEdmCollectionTypeReference edmPropertyType, object value, bool clearCollection, TimeZoneInfo timeZoneInfo = null)
+ IEdmCollectionTypeReference edmPropertyType, object value, bool clearCollection, ODataDeserializerContext context = null)
{
if (value != null)
{
@@ -134,7 +134,7 @@ internal static void SetCollectionProperty(object resource, string propertyName,
CollectionDeserializationHelpers.TryCreateInstance(propertyType, edmPropertyType, elementType, out newCollection))
{
// settable collections
- collection.AddToCollection(newCollection, elementType, resourceType, propertyName, propertyType, timeZoneInfo);
+ collection.AddToCollection(newCollection, elementType, resourceType, propertyName, propertyType, context);
if (propertyType.IsArray)
{
newCollection = CollectionDeserializationHelpers.ToArray(newCollection, elementType);
@@ -157,7 +157,7 @@ internal static void SetCollectionProperty(object resource, string propertyName,
newCollection.Clear(propertyName, resourceType);
}
- collection.AddToCollection(newCollection, elementType, resourceType, propertyName, propertyType, timeZoneInfo);
+ collection.AddToCollection(newCollection, elementType, resourceType, propertyName, propertyType, context);
}
}
}
diff --git a/src/Microsoft.AspNetCore.OData/Formatter/Deserialization/ODataDeserializerProvider.cs b/src/Microsoft.AspNetCore.OData/Formatter/Deserialization/ODataDeserializerProvider.cs
index d0392c8f9..0a7421f65 100644
--- a/src/Microsoft.AspNetCore.OData/Formatter/Deserialization/ODataDeserializerProvider.cs
+++ b/src/Microsoft.AspNetCore.OData/Formatter/Deserialization/ODataDeserializerProvider.cs
@@ -103,11 +103,7 @@ public virtual IODataDeserializer GetODataDeserializer(Type type, HttpRequest re
}
IEdmModel model = request.GetModel();
- //IODataTypeMappingProvider typeMappingProvider = _serviceProvider.GetRequiredService();
-
- ClrTypeCache typeMappingCache = model.GetTypeMappingCache();
- IEdmTypeReference edmType = typeMappingCache.GetEdmType(type, model);
- //IEdmTypeReference edmType = typeMappingProvider.GetEdmType(model, type);
+ IEdmTypeReference edmType = model.GetEdmTypeReference(type);
if (edmType == null)
{
diff --git a/src/Microsoft.AspNetCore.OData/Formatter/EdmLibHelper.cs b/src/Microsoft.AspNetCore.OData/Formatter/EdmLibHelper.cs
index fbb6cbf3b..0c584233c 100644
--- a/src/Microsoft.AspNetCore.OData/Formatter/EdmLibHelper.cs
+++ b/src/Microsoft.AspNetCore.OData/Formatter/EdmLibHelper.cs
@@ -50,7 +50,7 @@ internal static IEdmTypeReference GetExpectedPayloadType(Type type, ODataPath pa
else
{
TryGetInnerTypeForDelta(ref type);
- expectedPayloadType = model.GetTypeMappingCache().GetEdmType(type, model);
+ expectedPayloadType = model.GetEdmTypeReference(type);
}
return expectedPayloadType;
diff --git a/src/Microsoft.AspNetCore.OData/Formatter/ODataModelBinder.cs b/src/Microsoft.AspNetCore.OData/Formatter/ODataModelBinder.cs
index 9606ca230..d72b413e4 100644
--- a/src/Microsoft.AspNetCore.OData/Formatter/ODataModelBinder.cs
+++ b/src/Microsoft.AspNetCore.OData/Formatter/ODataModelBinder.cs
@@ -86,7 +86,8 @@ public Task BindModelAsync(ModelBindingContext bindingContext)
HttpRequest request = bindingContext.HttpContext.Request;
TimeZoneInfo timeZone = request.GetTimeZoneInfo();
- object model = ODataModelBinderConverter.ConvertTo(valueProviderResult.FirstValue, bindingContext.ModelType, timeZone);
+ IEdmModel edmModel = request.GetModel();
+ object model = ODataModelBinderConverter.ConvertTo(valueProviderResult.FirstValue, bindingContext.ModelType, timeZone, edmModel);
if (model != null)
{
bindingContext.Result = ModelBindingResult.Success(model);
diff --git a/src/Microsoft.AspNetCore.OData/Formatter/ODataModelBinderConverter.cs b/src/Microsoft.AspNetCore.OData/Formatter/ODataModelBinderConverter.cs
index a04af505b..bfd4b5051 100644
--- a/src/Microsoft.AspNetCore.OData/Formatter/ODataModelBinderConverter.cs
+++ b/src/Microsoft.AspNetCore.OData/Formatter/ODataModelBinderConverter.cs
@@ -94,7 +94,7 @@ public static object Convert(object graph, IEdmTypeReference edmTypeReference,
return ConvertResourceOrResourceSet(graph, edmTypeReference, readContext);
}
- internal static object ConvertTo(string valueString, Type type, TimeZoneInfo timeZone)
+ internal static object ConvertTo(string valueString, Type type, TimeZoneInfo timeZone, IEdmModel edmModel = null)
{
if (valueString == null)
{
@@ -137,8 +137,8 @@ internal static object ConvertTo(string valueString, Type type, TimeZoneInfo tim
// can return the correct Date object.
if (type == typeof(Date) || type == typeof(Date?))
{
- EdmCoreModel model = EdmCoreModel.Instance;
- IEdmPrimitiveTypeReference dateTypeReference = type.GetEdmPrimitiveTypeReference();
+ IEdmModel model = edmModel ?? EdmCoreModel.Instance;
+ IEdmPrimitiveTypeReference dateTypeReference = model.GetEdmPrimitiveTypeReference(type);
return ODataUriUtils.ConvertFromUriLiteral(valueString, ODataVersion.V4, model, dateTypeReference);
}
@@ -158,7 +158,7 @@ internal static object ConvertTo(string valueString, Type type, TimeZoneInfo tim
}
bool isNonStandardEdmPrimitive;
- type.IsNonstandardEdmPrimitive(out isNonStandardEdmPrimitive);
+ edmModel.IsNonstandardEdmPrimitive(type, out isNonStandardEdmPrimitive);
if (isNonStandardEdmPrimitive)
{
diff --git a/src/Microsoft.AspNetCore.OData/Formatter/Serialization/ODataSerializerContext.cs b/src/Microsoft.AspNetCore.OData/Formatter/Serialization/ODataSerializerContext.cs
index de37ac662..cfea75d5a 100644
--- a/src/Microsoft.AspNetCore.OData/Formatter/Serialization/ODataSerializerContext.cs
+++ b/src/Microsoft.AspNetCore.OData/Formatter/Serialization/ODataSerializerContext.cs
@@ -303,14 +303,13 @@ internal IEdmTypeReference GetEdmType(object instance, Type type)
throw Error.InvalidOperation(SRResources.RequestMustHaveModel);
}
- var typeMappingCache = Model.GetTypeMappingCache();
- edmType = typeMappingCache.GetEdmType(type, Model);
+ edmType = Model.GetEdmTypeReference(type);
if (edmType == null)
{
if (instance != null)
{
- edmType = typeMappingCache.GetEdmType(instance.GetType(), Model);
+ edmType = Model.GetEdmTypeReference(instance.GetType());
}
if (edmType == null)
@@ -320,7 +319,7 @@ internal IEdmTypeReference GetEdmType(object instance, Type type)
}
else if (instance != null)
{
- IEdmTypeReference actualType = typeMappingCache.GetEdmType(instance.GetType(), Model);
+ IEdmTypeReference actualType = Model.GetEdmTypeReference(instance.GetType());
if (actualType != null && actualType != edmType)
{
edmType = actualType;
diff --git a/src/Microsoft.AspNetCore.OData/Formatter/Serialization/ODataSerializerProvider.cs b/src/Microsoft.AspNetCore.OData/Formatter/Serialization/ODataSerializerProvider.cs
index 91407c940..ba53316c6 100644
--- a/src/Microsoft.AspNetCore.OData/Formatter/Serialization/ODataSerializerProvider.cs
+++ b/src/Microsoft.AspNetCore.OData/Formatter/Serialization/ODataSerializerProvider.cs
@@ -123,8 +123,7 @@ public virtual IODataSerializer GetODataPayloadSerializer(Type type, HttpRequest
IEdmModel model = request.GetModel();
// if it is not a special type, assume it has a corresponding EdmType.
- ClrTypeCache typeMappingCache = model.GetTypeMappingCache();
- IEdmTypeReference edmType = typeMappingCache.GetEdmType(type, model);
+ IEdmTypeReference edmType = model.GetEdmTypeReference(type);
if (edmType != null)
{
diff --git a/src/Microsoft.AspNetCore.OData/Microsoft.AspNetCore.OData.xml b/src/Microsoft.AspNetCore.OData/Microsoft.AspNetCore.OData.xml
index 46b2fceaa..afa14bee7 100644
--- a/src/Microsoft.AspNetCore.OData/Microsoft.AspNetCore.OData.xml
+++ b/src/Microsoft.AspNetCore.OData/Microsoft.AspNetCore.OData.xml
@@ -1920,42 +1920,109 @@
The output of method info.
True if the method info was found, false otherwise.
-
+
- The extensions used to map between C# types and Edm types.
+ The default implementation for .
+
+
+
+
+ Creates a static instance for the Default type mapper.
+
+
+
+
+ The default mapping between Edm primitive type and Clr primitive type.
+ Primitive types are cross Edm models.
-
+
- The mapping between Edm primitive type and Clr primitive type.
+ Item1 --> non-nullable
+ Item2 --> nullable
+
+
+
+
+ Gets the corresponding Edm primitive type for a given type.
+
+ The given CLR type.
+ Null or the Edm primitive type.
+
+
+
+ Gets the corresponding type for a given Edm primitive type .
+
+ The given Edm primitive type.
+ The nullable or not.
+ Null or the CLR type.
+
+
+
+ The cache used to hold the type mapping between and .
+
+
+
+
+ Gets the corresponding Edm type for the given CLR type .
+
+ The given Edm model.
+ The given CLR type.
+ Null or the corresponding Edm type reference.
+
+
+
+ Gets the corresponding for a given Edm type .
+
+ The Edm model.
+ The Edm type.
+ The nullable or not.
+ The assembly resolver. if it's null, will use the default resolver.
+ Null or the CLR type.
+
+
+
+ Finds the corresponding CLR type for a given Edm type reference.
+
+ The Edm model.
+ The Edm type.
+ The assembly resolver.
+ Null or the CLR type.
+
+
+
+ The extensions used to map between C# types and Edm types.
- Gets the corresponding Edm primitive type for the given CLR type.
+ Gets the corresponding Edm primitive type for a given type.
The given CLR type.
Null or the Edm primitive type.
-
+
- Gets the corresponding Edm primitive type for the given CLR type.
+ Gets the corresponding Edm primitive type for a given type.
+ The Edm model.
The given CLR type.
Null or the Edm primitive type.
-
+
Gets the corresponding CLR type for a given Edm primitive type.
+ The Edm model.
The given Edm primitive type.
Null or the CLR type.
-
+
Figures out if the given clr type is nonstandard edm primitive like uint, ushort, char[] etc.
and returns the corresponding clr type to which we map like uint => long.
+ The Edm model.
The potential non-standard CLR type.
A boolean value out to indicate whether the input CLR type is standard OData primitive type.
The standard CLR type or the input CLR type itself.
@@ -1995,7 +2062,7 @@
- Gets the corresponding CLR type for a given Edm type reference.
+ Gets the corresponding CLR type for a given Edm type.
The Edm model.
The Edm type.
@@ -2003,27 +2070,13 @@
- Gets the corresponding CLR type for a given Edm type reference.
+ Gets the corresponding CLR type for a given Edm type.
The Edm model.
The Edm type.
The assembly resolver.
Null or the CLR type.
-
-
- Check the input type is nullable type or not.
-
- The input CLR type.
- True/False.
-
-
-
- Check the input type is nullable or not.
-
- The test CRL type.
- True/False.
-
Provides the functionalities related to the Edm type.
@@ -2118,6 +2171,20 @@
The Edm model.
The Edm model name.
+
+
+ Gets the OData type mapping provider from the model.
+
+ The Edm model.
+ The .
+
+
+
+ Sets the OData type mapping provider to the model.
+
+ The Edm model.
+ The given mapper.
+
Gets the declared alternate keys of the most defined entity with a declared key present.
@@ -2345,6 +2412,85 @@
Gets the whole expand path.
+
+
+ Provides the mapping between CLR type and Edm type.
+
+
+
+
+ Gets the corresponding Edm primitive type for a given .
+
+ The given CLR type.
+ Null or the Edm primitive type.
+
+
+
+ Gets the corresponding for a given Edm primitive type .
+
+ The given Edm primitive type.
+ The nullable or not.
+ Null or the CLR type.
+
+
+
+ Gets the corresponding Edm type for the given CLR type .
+
+ The given Edm model.
+ The given CLR type.
+ Null or the corresponding Edm type reference.
+
+
+
+ Gets the corresponding for a given Edm type .
+
+ The given Edm model.
+ The given Edm type.
+ The nullable or not.
+ The assembly resolver.
+ Null or the CLR type.
+
+
+
+ Extension methods for .
+
+
+
+
+ Gets the corresponding for a given Edm primitive type .
+
+ The type mapper.
+ The Edm primitive type reference.
+ Null or the CLR type.
+
+
+
+ Gets the corresponding Edm type for the given CLR type .
+
+ The type mapper.
+ The given Edm model.
+ The given CLR type.
+ Null or the corresponding Edm type.
+
+
+
+ Gets the corresponding for a given Edm type .
+
+ The type mapper.
+ The Edm model.
+ The Edm type reference.
+ Null or the CLR type.
+
+
+
+ Gets the corresponding for a given Edm type .
+
+ The type mapper.
+ The Edm model.
+ The Edm type.
+ The assembly resolver.
+ Null or the CLR type.
+
The Edm model name annotation.
@@ -2584,6 +2730,18 @@
Gets a boolean indicating whether the link factory follows OData conventions or not.
+
+
+ to .
+
+
+
+
+ to .
+ item1: non-nullable
+ item2: nullable
+
+
The extension methods for .
diff --git a/src/Microsoft.AspNetCore.OData/PublicAPI.Unshipped.txt b/src/Microsoft.AspNetCore.OData/PublicAPI.Unshipped.txt
index 5601247d8..8bfbde015 100644
--- a/src/Microsoft.AspNetCore.OData/PublicAPI.Unshipped.txt
+++ b/src/Microsoft.AspNetCore.OData/PublicAPI.Unshipped.txt
@@ -222,6 +222,8 @@ Microsoft.AspNetCore.OData.Edm.CustomAggregateMethodAnnotation
Microsoft.AspNetCore.OData.Edm.CustomAggregateMethodAnnotation.AddMethod(string methodToken, System.Collections.Generic.IDictionary methods) -> Microsoft.AspNetCore.OData.Edm.CustomAggregateMethodAnnotation
Microsoft.AspNetCore.OData.Edm.CustomAggregateMethodAnnotation.CustomAggregateMethodAnnotation() -> void
Microsoft.AspNetCore.OData.Edm.CustomAggregateMethodAnnotation.GetMethodInfo(string methodToken, System.Type returnType, out System.Reflection.MethodInfo methodInfo) -> bool
+Microsoft.AspNetCore.OData.Edm.DefaultODataTypeMapper
+Microsoft.AspNetCore.OData.Edm.DefaultODataTypeMapper.DefaultODataTypeMapper() -> void
Microsoft.AspNetCore.OData.Edm.EdmModelAnnotationExtensions
Microsoft.AspNetCore.OData.Edm.EdmModelLinkBuilderExtensions
Microsoft.AspNetCore.OData.Edm.EntitySelfLinks
@@ -232,6 +234,12 @@ Microsoft.AspNetCore.OData.Edm.EntitySelfLinks.IdLink.get -> System.Uri
Microsoft.AspNetCore.OData.Edm.EntitySelfLinks.IdLink.set -> void
Microsoft.AspNetCore.OData.Edm.EntitySelfLinks.ReadLink.get -> System.Uri
Microsoft.AspNetCore.OData.Edm.EntitySelfLinks.ReadLink.set -> void
+Microsoft.AspNetCore.OData.Edm.IODataTypeMapper
+Microsoft.AspNetCore.OData.Edm.IODataTypeMapper.GetClrType(Microsoft.OData.Edm.IEdmModel edmModel, Microsoft.OData.Edm.IEdmType edmType, bool nullable, Microsoft.OData.ModelBuilder.IAssemblyResolver assembliesResolver) -> System.Type
+Microsoft.AspNetCore.OData.Edm.IODataTypeMapper.GetEdmTypeReference(Microsoft.OData.Edm.IEdmModel edmModel, System.Type clrType) -> Microsoft.OData.Edm.IEdmTypeReference
+Microsoft.AspNetCore.OData.Edm.IODataTypeMapper.GetPrimitiveType(Microsoft.OData.Edm.IEdmPrimitiveType primitiveType, bool nullable) -> System.Type
+Microsoft.AspNetCore.OData.Edm.IODataTypeMapper.GetPrimitiveType(System.Type clrType) -> Microsoft.OData.Edm.IEdmPrimitiveTypeReference
+Microsoft.AspNetCore.OData.Edm.IODataTypeMapperExtensions
Microsoft.AspNetCore.OData.Edm.ModelNameAnnotation
Microsoft.AspNetCore.OData.Edm.ModelNameAnnotation.ModelName.get -> string
Microsoft.AspNetCore.OData.Edm.ModelNameAnnotation.ModelNameAnnotation(string name) -> void
@@ -1450,7 +1458,9 @@ static Microsoft.AspNetCore.OData.Edm.EdmModelAnnotationExtensions.GetClrPropert
static Microsoft.AspNetCore.OData.Edm.EdmModelAnnotationExtensions.GetConcurrencyProperties(this Microsoft.OData.Edm.IEdmModel model, Microsoft.OData.Edm.IEdmNavigationSource navigationSource) -> System.Collections.Generic.IEnumerable
static Microsoft.AspNetCore.OData.Edm.EdmModelAnnotationExtensions.GetDynamicPropertyDictionary(this Microsoft.OData.Edm.IEdmModel edmModel, Microsoft.OData.Edm.IEdmStructuredType edmType) -> System.Reflection.PropertyInfo
static Microsoft.AspNetCore.OData.Edm.EdmModelAnnotationExtensions.GetModelName(this Microsoft.OData.Edm.IEdmModel model) -> string
+static Microsoft.AspNetCore.OData.Edm.EdmModelAnnotationExtensions.GetTypeMapper(this Microsoft.OData.Edm.IEdmModel model) -> Microsoft.AspNetCore.OData.Edm.IODataTypeMapper
static Microsoft.AspNetCore.OData.Edm.EdmModelAnnotationExtensions.SetModelName(this Microsoft.OData.Edm.IEdmModel model, string name) -> void
+static Microsoft.AspNetCore.OData.Edm.EdmModelAnnotationExtensions.SetTypeMapper(this Microsoft.OData.Edm.IEdmModel model, Microsoft.AspNetCore.OData.Edm.IODataTypeMapper mapper) -> void
static Microsoft.AspNetCore.OData.Edm.EdmModelLinkBuilderExtensions.GetNavigationSourceLinkBuilder(this Microsoft.OData.Edm.IEdmModel model, Microsoft.OData.Edm.IEdmNavigationSource navigationSource) -> Microsoft.AspNetCore.OData.Edm.NavigationSourceLinkBuilderAnnotation
static Microsoft.AspNetCore.OData.Edm.EdmModelLinkBuilderExtensions.GetOperationLinkBuilder(this Microsoft.OData.Edm.IEdmModel model, Microsoft.OData.Edm.IEdmOperation operation) -> Microsoft.AspNetCore.OData.Edm.OperationLinkBuilder
static Microsoft.AspNetCore.OData.Edm.EdmModelLinkBuilderExtensions.HasEditLink(this Microsoft.OData.Edm.IEdmModel model, Microsoft.OData.Edm.IEdmNavigationSource navigationSource, Microsoft.AspNetCore.OData.Edm.SelfLinkBuilder editLinkBuilder) -> void
@@ -1459,6 +1469,10 @@ static Microsoft.AspNetCore.OData.Edm.EdmModelLinkBuilderExtensions.HasNavigatio
static Microsoft.AspNetCore.OData.Edm.EdmModelLinkBuilderExtensions.HasReadLink(this Microsoft.OData.Edm.IEdmModel model, Microsoft.OData.Edm.IEdmNavigationSource navigationSource, Microsoft.AspNetCore.OData.Edm.SelfLinkBuilder readLinkBuilder) -> void
static Microsoft.AspNetCore.OData.Edm.EdmModelLinkBuilderExtensions.SetNavigationSourceLinkBuilder(this Microsoft.OData.Edm.IEdmModel model, Microsoft.OData.Edm.IEdmNavigationSource navigationSource, Microsoft.AspNetCore.OData.Edm.NavigationSourceLinkBuilderAnnotation navigationSourceLinkBuilder) -> void
static Microsoft.AspNetCore.OData.Edm.EdmModelLinkBuilderExtensions.SetOperationLinkBuilder(this Microsoft.OData.Edm.IEdmModel model, Microsoft.OData.Edm.IEdmOperation operation, Microsoft.AspNetCore.OData.Edm.OperationLinkBuilder operationLinkBuilder) -> void
+static Microsoft.AspNetCore.OData.Edm.IODataTypeMapperExtensions.GetClrType(this Microsoft.AspNetCore.OData.Edm.IODataTypeMapper mapper, Microsoft.OData.Edm.IEdmModel edmModel, Microsoft.OData.Edm.IEdmTypeReference edmType) -> System.Type
+static Microsoft.AspNetCore.OData.Edm.IODataTypeMapperExtensions.GetClrType(this Microsoft.AspNetCore.OData.Edm.IODataTypeMapper mapper, Microsoft.OData.Edm.IEdmModel edmModel, Microsoft.OData.Edm.IEdmTypeReference edmType, Microsoft.OData.ModelBuilder.IAssemblyResolver assembliesResolver) -> System.Type
+static Microsoft.AspNetCore.OData.Edm.IODataTypeMapperExtensions.GetEdmType(this Microsoft.AspNetCore.OData.Edm.IODataTypeMapper mapper, Microsoft.OData.Edm.IEdmModel edmModel, System.Type clrType) -> Microsoft.OData.Edm.IEdmType
+static Microsoft.AspNetCore.OData.Edm.IODataTypeMapperExtensions.GetPrimitiveType(this Microsoft.AspNetCore.OData.Edm.IODataTypeMapper mapper, Microsoft.OData.Edm.IEdmPrimitiveTypeReference primitiveType) -> System.Type
static Microsoft.AspNetCore.OData.Extensions.ActionModelExtensions.AddSelector(this Microsoft.AspNetCore.Mvc.ApplicationModels.ActionModel action, string httpMethods, string prefix, Microsoft.OData.Edm.IEdmModel model, Microsoft.AspNetCore.OData.Routing.Template.ODataPathTemplate path, Microsoft.AspNetCore.OData.Routing.ODataRouteOptions options = null) -> void
static Microsoft.AspNetCore.OData.Extensions.ActionModelExtensions.GetAttribute(this Microsoft.AspNetCore.Mvc.ApplicationModels.ActionModel action) -> T
static Microsoft.AspNetCore.OData.Extensions.ActionModelExtensions.HasODataKeyParameter(this Microsoft.AspNetCore.Mvc.ApplicationModels.ActionModel action, Microsoft.OData.Edm.IEdmEntityType entityType, string keyPrefix = "key") -> bool
@@ -1555,6 +1569,10 @@ virtual Microsoft.AspNetCore.OData.Batch.UnbufferedODataBatchHandler.ExecuteChan
virtual Microsoft.AspNetCore.OData.Batch.UnbufferedODataBatchHandler.ExecuteOperationAsync(Microsoft.OData.ODataBatchReader batchReader, System.Guid batchId, Microsoft.AspNetCore.Http.HttpRequest originalRequest, Microsoft.AspNetCore.Http.RequestDelegate handler) -> System.Threading.Tasks.Task
virtual Microsoft.AspNetCore.OData.Deltas.Delta.ExpectedClrType.get -> System.Type
virtual Microsoft.AspNetCore.OData.Deltas.Delta.StructuredType.get -> System.Type
+virtual Microsoft.AspNetCore.OData.Edm.DefaultODataTypeMapper.GetClrType(Microsoft.OData.Edm.IEdmModel edmModel, Microsoft.OData.Edm.IEdmType edmType, bool nullable, Microsoft.OData.ModelBuilder.IAssemblyResolver assembliesResolver) -> System.Type
+virtual Microsoft.AspNetCore.OData.Edm.DefaultODataTypeMapper.GetEdmTypeReference(Microsoft.OData.Edm.IEdmModel edmModel, System.Type clrType) -> Microsoft.OData.Edm.IEdmTypeReference
+virtual Microsoft.AspNetCore.OData.Edm.DefaultODataTypeMapper.GetPrimitiveType(Microsoft.OData.Edm.IEdmPrimitiveType primitiveType, bool nullable) -> System.Type
+virtual Microsoft.AspNetCore.OData.Edm.DefaultODataTypeMapper.GetPrimitiveType(System.Type clrType) -> Microsoft.OData.Edm.IEdmPrimitiveTypeReference
virtual Microsoft.AspNetCore.OData.Edm.NavigationSourceLinkBuilderAnnotation.BuildEditLink(Microsoft.AspNetCore.OData.Formatter.ResourceContext instanceContext, Microsoft.AspNetCore.OData.Formatter.ODataMetadataLevel metadataLevel, System.Uri idLink) -> System.Uri
virtual Microsoft.AspNetCore.OData.Edm.NavigationSourceLinkBuilderAnnotation.BuildEntitySelfLinks(Microsoft.AspNetCore.OData.Formatter.ResourceContext instanceContext, Microsoft.AspNetCore.OData.Formatter.ODataMetadataLevel metadataLevel) -> Microsoft.AspNetCore.OData.Edm.EntitySelfLinks
virtual Microsoft.AspNetCore.OData.Edm.NavigationSourceLinkBuilderAnnotation.BuildIdLink(Microsoft.AspNetCore.OData.Formatter.ResourceContext instanceContext, Microsoft.AspNetCore.OData.Formatter.ODataMetadataLevel metadataLevel) -> System.Uri
diff --git a/src/Microsoft.AspNetCore.OData/Query/EnableQueryAttribute.cs b/src/Microsoft.AspNetCore.OData/Query/EnableQueryAttribute.cs
index a41e87aea..cf673463c 100644
--- a/src/Microsoft.AspNetCore.OData/Query/EnableQueryAttribute.cs
+++ b/src/Microsoft.AspNetCore.OData/Query/EnableQueryAttribute.cs
@@ -88,9 +88,7 @@ public override void OnActionExecuting(ActionExecutingContext actionExecutingCon
return;
}
- Type clrType = edmModel.GetTypeMappingCache().GetClrType(
- elementType.ToEdmTypeReference(isNullable: false),
- edmModel);
+ Type clrType = edmModel.GetClrType(elementType.ToEdmTypeReference(isNullable: false));
// CLRType can be missing if untyped registrations were made.
if (clrType != null)
@@ -726,7 +724,7 @@ private static bool ContainsAutoSelectExpandProperty(object responseValue, IQuer
{
throw Error.InvalidOperation(SRResources.QueryGetModelMustNotReturnNull);
}
- IEdmType edmType = model.GetTypeMappingCache().GetEdmType(elementClrType, model)?.Definition;
+ IEdmType edmType = model.GetEdmTypeReference(elementClrType)?.Definition;
IEdmStructuredType structuredType = edmType as IEdmStructuredType;
ODataPath path = request.ODataFeature().Path;
diff --git a/src/Microsoft.AspNetCore.OData/Query/Expressions/AggregationBinder.cs b/src/Microsoft.AspNetCore.OData/Query/Expressions/AggregationBinder.cs
index 2288b2e90..982060916 100644
--- a/src/Microsoft.AspNetCore.OData/Query/Expressions/AggregationBinder.cs
+++ b/src/Microsoft.AspNetCore.OData/Query/Expressions/AggregationBinder.cs
@@ -104,7 +104,10 @@ private AggregateExpression FixCustomMethodReturnType(AggregateExpression expres
}
var customMethod = GetCustomMethod(expression);
- var typeReference = customMethod.ReturnType.GetEdmPrimitiveTypeReference();
+
+ // var typeReference = customMethod.ReturnType.GetEdmPrimitiveTypeReference();
+ var typeReference = Model.GetEdmPrimitiveTypeReference(customMethod.ReturnType);
+
return new AggregateExpression(expression.Expression, expression.MethodDefinition, expression.Alias, typeReference);
}
diff --git a/src/Microsoft.AspNetCore.OData/Query/Expressions/ExpressionBinderBase.cs b/src/Microsoft.AspNetCore.OData/Query/Expressions/ExpressionBinderBase.cs
index bad9ee3fa..0985ff1cb 100644
--- a/src/Microsoft.AspNetCore.OData/Query/Expressions/ExpressionBinderBase.cs
+++ b/src/Microsoft.AspNetCore.OData/Query/Expressions/ExpressionBinderBase.cs
@@ -337,10 +337,10 @@ private Expression BindIsOf(SingleValueFunctionCallNode node)
return FalseConstant;
}
- bool isSourcePrimitiveOrEnum = source.Type.GetEdmPrimitiveType() != null ||
+ bool isSourcePrimitiveOrEnum = Model.GetEdmPrimitiveTypeReference(source.Type) != null ||
TypeHelper.IsEnum(source.Type);
- bool isTargetPrimitiveOrEnum = clrType.GetEdmPrimitiveType() != null ||
+ bool isTargetPrimitiveOrEnum = Model.GetEdmPrimitiveTypeReference(clrType) != null ||
TypeHelper.IsEnum(clrType);
if (isSourcePrimitiveOrEnum && isTargetPrimitiveOrEnum)
@@ -731,7 +731,7 @@ private Expression BindCastSingleValue(SingleValueFunctionCallNode node)
}
if ((!targetEdmTypeReference.IsPrimitive() && !targetEdmTypeReference.IsEnum()) ||
- (source.Type.GetEdmPrimitiveType() == null && !TypeHelper.IsEnum(source.Type)))
+ (Model.GetEdmPrimitiveTypeReference(source.Type) == null && !TypeHelper.IsEnum(source.Type)))
{
// Cast fails and return null.
return NullConstant;
@@ -1065,7 +1065,7 @@ internal static Expression GetPropertyExpression(Expression source, string prope
internal Expression ConvertNonStandardPrimitives(Expression source)
{
bool isNonstandardEdmPrimitive;
- Type conversionType = source.Type.IsNonstandardEdmPrimitive(out isNonstandardEdmPrimitive);
+ Type conversionType = Model.IsNonstandardEdmPrimitive(source.Type, out isNonstandardEdmPrimitive);
if (isNonstandardEdmPrimitive)
{
diff --git a/src/Microsoft.AspNetCore.OData/Query/Expressions/ExpressionBinderHelper.cs b/src/Microsoft.AspNetCore.OData/Query/Expressions/ExpressionBinderHelper.cs
index 5e13f6499..bd0b29dcb 100644
--- a/src/Microsoft.AspNetCore.OData/Query/Expressions/ExpressionBinderHelper.cs
+++ b/src/Microsoft.AspNetCore.OData/Query/Expressions/ExpressionBinderHelper.cs
@@ -154,8 +154,7 @@ public static Expression CreateBinaryExpression(BinaryOperatorKind binaryOperato
case ExpressionType.NotEqual:
return Expression.MakeBinary(binaryExpressionType, left, right, liftToNull, method: Linq2ObjectsComparisonMethods.AreByteArraysNotEqualMethodInfo);
default:
- IEdmPrimitiveType binaryType = typeof(byte[]).GetEdmPrimitiveType();
- throw new ODataException(Error.Format(SRResources.BinaryOperatorNotSupported, binaryType.FullName(), binaryType.FullName(), binaryOperator));
+ throw new ODataException(Error.Format(SRResources.BinaryOperatorNotSupported, "Edm.Binary", "Edm.Binary", binaryOperator));
}
}
else
diff --git a/src/Microsoft.AspNetCore.OData/Query/ODataQueryContext.cs b/src/Microsoft.AspNetCore.OData/Query/ODataQueryContext.cs
index 3f2905a84..003499123 100644
--- a/src/Microsoft.AspNetCore.OData/Query/ODataQueryContext.cs
+++ b/src/Microsoft.AspNetCore.OData/Query/ODataQueryContext.cs
@@ -52,7 +52,7 @@ public ODataQueryContext(IEdmModel model, Type elementClrType, ODataPath path)
throw Error.ArgumentNull(nameof(elementClrType));
}
- ElementType = model.GetTypeMappingCache().GetEdmType(elementClrType, model)?.Definition;
+ ElementType = model.GetEdmTypeReference(elementClrType)?.Definition;
if (ElementType == null)
{
diff --git a/src/Microsoft.AspNetCore.OData/Query/Query/DefaultSkipTokenHandler.cs b/src/Microsoft.AspNetCore.OData/Query/Query/DefaultSkipTokenHandler.cs
index 36f31a68b..479c9ec8a 100644
--- a/src/Microsoft.AspNetCore.OData/Query/Query/DefaultSkipTokenHandler.cs
+++ b/src/Microsoft.AspNetCore.OData/Query/Query/DefaultSkipTokenHandler.cs
@@ -427,7 +427,7 @@ internal static IEdmType GetTypeFromObject(object value, IEdmModel model)
}
Type clrType = value.GetType();
- return model.GetTypeMappingCache().GetEdmType(clrType, model)?.Definition;
+ return model.GetEdmTypeReference(clrType)?.Definition;
}
private static IList ParseValue(string value, char delim)
diff --git a/src/Microsoft.AspNetCore.OData/Query/Wrapper/SelectExpandWrapper.cs b/src/Microsoft.AspNetCore.OData/Query/Wrapper/SelectExpandWrapper.cs
index 14dc2d7f8..d74171d1a 100644
--- a/src/Microsoft.AspNetCore.OData/Query/Wrapper/SelectExpandWrapper.cs
+++ b/src/Microsoft.AspNetCore.OData/Query/Wrapper/SelectExpandWrapper.cs
@@ -68,7 +68,7 @@ public IEdmTypeReference GetEdmType()
Type elementType = GetElementType();
- return model.GetTypeMappingCache().GetEdmType(elementType, model);
+ return model.GetEdmTypeReference(elementType);
}
///
diff --git a/src/Microsoft.AspNetCore.OData/Results/ResultHelpers.cs b/src/Microsoft.AspNetCore.OData/Results/ResultHelpers.cs
index a851c8260..029d833f5 100644
--- a/src/Microsoft.AspNetCore.OData/Results/ResultHelpers.cs
+++ b/src/Microsoft.AspNetCore.OData/Results/ResultHelpers.cs
@@ -171,7 +171,7 @@ private static Uri GenerateContainmentODataPathSegments(ResourceContext resource
private static IEdmEntityTypeReference GetEntityType(IEdmModel model, object entity)
{
Type entityType = entity.GetType();
- IEdmTypeReference edmType = model.GetTypeMappingCache().GetEdmType(entityType, model);
+ IEdmTypeReference edmType = model.GetEdmTypeReference(entityType);
if (edmType == null)
{
throw Error.InvalidOperation(SRResources.ResourceTypeNotInModel, entityType.FullName);
diff --git a/test/Microsoft.AspNetCore.OData.Tests/Edm/DefaultODataTypeMapperTests.cs b/test/Microsoft.AspNetCore.OData.Tests/Edm/DefaultODataTypeMapperTests.cs
new file mode 100644
index 000000000..2e1cd1e1e
--- /dev/null
+++ b/test/Microsoft.AspNetCore.OData.Tests/Edm/DefaultODataTypeMapperTests.cs
@@ -0,0 +1,494 @@
+//-----------------------------------------------------------------------------
+//
+// Copyright (c) .NET Foundation and Contributors. All rights reserved.
+// See License.txt in the project root for license information.
+//
+//------------------------------------------------------------------------------
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Reflection;
+using System.Xml.Linq;
+using Microsoft.AspNetCore.OData.Edm;
+using Microsoft.AspNetCore.OData.Tests.Commons;
+using Microsoft.OData.Edm;
+using Microsoft.OData.ModelBuilder;
+using Microsoft.Spatial;
+using Moq;
+using Xunit;
+
+namespace Microsoft.AspNetCore.OData.Tests.Edm
+{
+ public class DefaultODataTypeMapperTests
+ {
+ private static IEdmModel EdmModel = GetEdmModel();
+ private DefaultODataTypeMapper _mapper = new DefaultODataTypeMapper();
+
+ #region PrimitiveType
+ [Theory]
+ [InlineData(typeof(string), "Edm.String", true)]
+ [InlineData(typeof(bool), "Edm.Boolean", false)]
+ [InlineData(typeof(bool?), "Edm.Boolean", true)]
+ [InlineData(typeof(byte), "Edm.Byte", false)]
+ [InlineData(typeof(byte?), "Edm.Byte", true)]
+ [InlineData(typeof(decimal), "Edm.Decimal", false)]
+ [InlineData(typeof(decimal?), "Edm.Decimal", true)]
+ [InlineData(typeof(double), "Edm.Double", false)]
+ [InlineData(typeof(double?), "Edm.Double", true)]
+ [InlineData(typeof(Guid), "Edm.Guid", false)]
+ [InlineData(typeof(Guid?), "Edm.Guid", true)]
+ [InlineData(typeof(short), "Edm.Int16", false)]
+ [InlineData(typeof(short?), "Edm.Int16", true)]
+ [InlineData(typeof(int), "Edm.Int32", false)]
+ [InlineData(typeof(int?), "Edm.Int32", true)]
+ [InlineData(typeof(long), "Edm.Int64", false)]
+ [InlineData(typeof(long?), "Edm.Int64", true)]
+ [InlineData(typeof(sbyte), "Edm.SByte", false)]
+ [InlineData(typeof(sbyte?), "Edm.SByte", true)]
+ [InlineData(typeof(float), "Edm.Single", false)]
+ [InlineData(typeof(float?), "Edm.Single", true)]
+ [InlineData(typeof(DateTimeOffset), "Edm.DateTimeOffset", false)]
+ [InlineData(typeof(DateTimeOffset?), "Edm.DateTimeOffset", true)]
+ [InlineData(typeof(TimeSpan), "Edm.Duration", false)]
+ [InlineData(typeof(TimeSpan?), "Edm.Duration", true)]
+ [InlineData(typeof(Date), "Edm.Date", false)]
+ [InlineData(typeof(Date?), "Edm.Date", true)]
+ [InlineData(typeof(TimeOfDay), "Edm.TimeOfDay", false)]
+ [InlineData(typeof(TimeOfDay?), "Edm.TimeOfDay", true)]
+ [InlineData(typeof(byte[]), "Edm.Binary", true)]
+ [InlineData(typeof(Stream), "Edm.Stream", true)]
+ public void GetPrimitiveType_ForClrType_WorksAsExpected_ForStandardPrimitive(Type clrType, string name, bool nullable)
+ {
+ // Arrange & Act
+ IEdmPrimitiveTypeReference primitiveTypeReference = _mapper.GetPrimitiveType(clrType);
+
+ // Assert
+ Assert.NotNull(primitiveTypeReference);
+ Assert.Equal(name, primitiveTypeReference.FullName());
+ Assert.Equal(nullable, primitiveTypeReference.IsNullable);
+ }
+
+ [Theory]
+ [InlineData(typeof(XElement), "Edm.String", true)]
+ [InlineData(typeof(ushort), "Edm.Int32", false)]
+ [InlineData(typeof(ushort?), "Edm.Int32", true)]
+ [InlineData(typeof(uint), "Edm.Int64", false)]
+ [InlineData(typeof(uint?), "Edm.Int64", true)]
+ [InlineData(typeof(ulong), "Edm.Int64", false)]
+ [InlineData(typeof(ulong?), "Edm.Int64", true)]
+ [InlineData(typeof(char[]), "Edm.String", true)]
+ [InlineData(typeof(char), "Edm.String", false)]
+ [InlineData(typeof(char?), "Edm.String", true)]
+ [InlineData(typeof(DateTime), "Edm.DateTimeOffset", false)]
+ [InlineData(typeof(DateTime?), "Edm.DateTimeOffset", true)]
+ public void GetPrimitiveType_ForClrType_WorksAsExpected_ForNonStandardPrimitive(Type clrType, string name, bool nullable)
+ {
+ // Arrange & Act
+ IEdmPrimitiveTypeReference primitiveTypeReference = _mapper.GetPrimitiveType(clrType);
+
+ // Assert
+ Assert.NotNull(primitiveTypeReference);
+ Assert.Equal(name, primitiveTypeReference.FullName());
+ Assert.Equal(nullable, primitiveTypeReference.IsNullable);
+ }
+
+ [Theory]
+ [InlineData(typeof(Geography), "Edm.Geography")]
+ [InlineData(typeof(GeographyPoint), "Edm.GeographyPoint")]
+ [InlineData(typeof(GeographyLineString), "Edm.GeographyLineString")]
+ [InlineData(typeof(GeographyPolygon), "Edm.GeographyPolygon")]
+ [InlineData(typeof(GeographyCollection), "Edm.GeographyCollection")]
+ [InlineData(typeof(GeographyMultiLineString), "Edm.GeographyMultiLineString")]
+ [InlineData(typeof(GeographyMultiPoint), "Edm.GeographyMultiPoint")]
+ [InlineData(typeof(GeographyMultiPolygon), "Edm.GeographyMultiPolygon")]
+ [InlineData(typeof(Geometry), "Edm.Geometry")]
+ [InlineData(typeof(GeometryPoint), "Edm.GeometryPoint")]
+ [InlineData(typeof(GeometryLineString), "Edm.GeometryLineString")]
+ [InlineData(typeof(GeometryPolygon), "Edm.GeometryPolygon")]
+ [InlineData(typeof(GeometryCollection), "Edm.GeometryCollection")]
+ [InlineData(typeof(GeometryMultiLineString), "Edm.GeometryMultiLineString")]
+ [InlineData(typeof(GeometryMultiPoint), "Edm.GeometryMultiPoint")]
+ [InlineData(typeof(GeometryMultiPolygon), "Edm.GeometryMultiPolygon")]
+ public void GetPrimitiveType_ForClrType_WorksAsExpected_ForSpatialPrimitive(Type clrType, string name)
+ {
+ // Arrange & Act
+ IEdmPrimitiveTypeReference primitiveTypeReference = _mapper.GetPrimitiveType(clrType);
+
+ // Assert
+ Assert.NotNull(primitiveTypeReference);
+ Assert.Equal(name, primitiveTypeReference.FullName());
+ Assert.True(primitiveTypeReference.IsNullable);
+ }
+
+ [Theory]
+ [InlineData(EdmPrimitiveTypeKind.String, typeof(string), typeof(string))]
+ [InlineData(EdmPrimitiveTypeKind.Boolean, typeof(bool?), typeof(bool))]
+ [InlineData(EdmPrimitiveTypeKind.Byte, typeof(byte?), typeof(byte))]
+ [InlineData(EdmPrimitiveTypeKind.Decimal, typeof(decimal?), typeof(decimal))]
+ [InlineData(EdmPrimitiveTypeKind.Double, typeof(double?), typeof(double))]
+ [InlineData(EdmPrimitiveTypeKind.Guid, typeof(Guid?), typeof(Guid))]
+ [InlineData(EdmPrimitiveTypeKind.Int16, typeof(short?), typeof(short))]
+ [InlineData(EdmPrimitiveTypeKind.Int32, typeof(int?), typeof(int))]
+ [InlineData(EdmPrimitiveTypeKind.Int64, typeof(long?), typeof(long))]
+ [InlineData(EdmPrimitiveTypeKind.SByte, typeof(sbyte?), typeof(sbyte))]
+ [InlineData(EdmPrimitiveTypeKind.Single, typeof(float?), typeof(float))]
+ [InlineData(EdmPrimitiveTypeKind.DateTimeOffset, typeof(DateTimeOffset?), typeof(DateTimeOffset))]
+ [InlineData(EdmPrimitiveTypeKind.Duration, typeof(TimeSpan?), typeof(TimeSpan))]
+ [InlineData(EdmPrimitiveTypeKind.Date, typeof(Date?), typeof(Date))]
+ [InlineData(EdmPrimitiveTypeKind.TimeOfDay, typeof(TimeOfDay?), typeof(TimeOfDay))]
+ [InlineData(EdmPrimitiveTypeKind.Binary, typeof(byte[]), typeof(byte[]))]
+ [InlineData(EdmPrimitiveTypeKind.Stream, typeof(Stream), typeof(Stream))]
+ public void GetPrimitiveType_ForEdmType_WorksAsExpected_ForStandardPrimitive(EdmPrimitiveTypeKind kind, Type nullExpected, Type nonNullExpected)
+ {
+ // Arrange & Act & Assert
+ IEdmPrimitiveType primitiveType = EdmCoreModel.Instance.GetPrimitiveType(kind);
+ Type clrType = _mapper.GetPrimitiveType(primitiveType, true);
+ Assert.Equal(nullExpected, clrType);
+
+ // Arrange & Act & Assert
+ clrType = _mapper.GetPrimitiveType(primitiveType, false);
+ Assert.Equal(nonNullExpected, clrType);
+ }
+
+ [Theory]
+ [InlineData(EdmPrimitiveTypeKind.Geography, typeof(Geography))]
+ [InlineData(EdmPrimitiveTypeKind.GeographyPoint, typeof(GeographyPoint))]
+ [InlineData(EdmPrimitiveTypeKind.GeographyLineString, typeof(GeographyLineString))]
+ [InlineData(EdmPrimitiveTypeKind.GeographyPolygon, typeof(GeographyPolygon))]
+ [InlineData(EdmPrimitiveTypeKind.GeographyCollection, typeof(GeographyCollection))]
+ [InlineData(EdmPrimitiveTypeKind.GeographyMultiLineString, typeof(GeographyMultiLineString))]
+ [InlineData(EdmPrimitiveTypeKind.GeographyMultiPoint, typeof(GeographyMultiPoint))]
+ [InlineData(EdmPrimitiveTypeKind.GeographyMultiPolygon, typeof(GeographyMultiPolygon))]
+ [InlineData(EdmPrimitiveTypeKind.Geometry, typeof(Geometry))]
+ [InlineData(EdmPrimitiveTypeKind.GeometryPoint, typeof(GeometryPoint))]
+ [InlineData(EdmPrimitiveTypeKind.GeometryLineString, typeof(GeometryLineString))]
+ [InlineData(EdmPrimitiveTypeKind.GeometryPolygon, typeof(GeometryPolygon))]
+ [InlineData(EdmPrimitiveTypeKind.GeometryCollection, typeof(GeometryCollection))]
+ [InlineData(EdmPrimitiveTypeKind.GeometryMultiLineString, typeof(GeometryMultiLineString))]
+ [InlineData(EdmPrimitiveTypeKind.GeometryMultiPoint, typeof(GeometryMultiPoint))]
+ [InlineData(EdmPrimitiveTypeKind.GeometryMultiPolygon, typeof(GeometryMultiPolygon))]
+ public void GetPrimitiveType_ForEdmType_WorksAsExpected_ForSpatialPrimitive(EdmPrimitiveTypeKind kind, Type expected)
+ {
+ // Arrange & Act & Assert
+ IEdmPrimitiveType primitiveType = EdmCoreModel.Instance.GetPrimitiveType(kind);
+ Type clrType = _mapper.GetPrimitiveType(primitiveType, true);
+ Assert.Equal(expected, clrType);
+
+ // Arrange & Act & Assert
+ clrType = _mapper.GetPrimitiveType(primitiveType, false);
+ Assert.Equal(expected, clrType);
+ }
+
+ [Theory]
+ [InlineData(EdmPrimitiveTypeKind.None)]
+ [InlineData(EdmPrimitiveTypeKind.PrimitiveType)]
+ public void GetPrimitiveType_ForEdmType_WorksAsExpected_ForNotUsedKind(EdmPrimitiveTypeKind kind)
+ {
+ // Arrange & Act & Assert
+ IEdmPrimitiveType primitiveType = EdmCoreModel.Instance.GetPrimitiveType(kind);
+ Type clrType = _mapper.GetPrimitiveType(primitiveType, true);
+ Assert.Null(clrType);
+
+ // Arrange & Act & Assert
+ clrType = _mapper.GetPrimitiveType(primitiveType, false);
+ Assert.Null(clrType);
+ }
+ #endregion
+
+ #region GetClrType
+ [Fact]
+ public void GetClrType_ThrowsArgumentNull_ForInputParameters()
+ {
+ // Arrange & Act & Assert
+ Mock edmType = new Mock();
+ edmType.Setup(x => x.TypeKind).Returns(EdmTypeKind.Entity);
+ ExceptionAssert.ThrowsArgumentNull(() => _mapper.GetClrType(null, edmType.Object, true, null), "edmModel");
+
+ IEdmModel model = new Mock().Object;
+ IAssemblyResolver resolver = new Mock().Object;
+ ExceptionAssert.ThrowsArgumentNull(() => _mapper.GetClrType(model, null, true, resolver), "edmType");
+ }
+
+ [Theory]
+ [InlineData(EdmPrimitiveTypeKind.String, typeof(string))]
+ [InlineData(EdmPrimitiveTypeKind.Boolean, typeof(bool))]
+ [InlineData(EdmPrimitiveTypeKind.Byte, typeof(byte))]
+ [InlineData(EdmPrimitiveTypeKind.Decimal, typeof(decimal))]
+ [InlineData(EdmPrimitiveTypeKind.Double, typeof(double))]
+ [InlineData(EdmPrimitiveTypeKind.Guid, typeof(Guid))]
+ [InlineData(EdmPrimitiveTypeKind.Int16, typeof(short))]
+ [InlineData(EdmPrimitiveTypeKind.Int32, typeof(int))]
+ [InlineData(EdmPrimitiveTypeKind.Int64, typeof(long))]
+ [InlineData(EdmPrimitiveTypeKind.SByte, typeof(sbyte))]
+ [InlineData(EdmPrimitiveTypeKind.Single, typeof(float))]
+ [InlineData(EdmPrimitiveTypeKind.Binary, typeof(byte[]))]
+ [InlineData(EdmPrimitiveTypeKind.Stream, typeof(Stream))]
+ [InlineData(EdmPrimitiveTypeKind.DateTimeOffset, typeof(DateTimeOffset))]
+ [InlineData(EdmPrimitiveTypeKind.Duration, typeof(TimeSpan))]
+ [InlineData(EdmPrimitiveTypeKind.Date, typeof(Date))]
+ [InlineData(EdmPrimitiveTypeKind.TimeOfDay, typeof(TimeOfDay))]
+ public void GetClrType_WorksAsExpected_ForStandardPrimitive(EdmPrimitiveTypeKind kind, Type expected)
+ {
+ // #1 Arrange & Act & Assert for nullable equals to false
+ IEdmPrimitiveType primitiveType = EdmCoreModel.Instance.GetPrimitiveType(kind);
+ Type clrType = _mapper.GetClrType(EdmModel, primitiveType, false, assembliesResolver: null);
+ Assert.Equal(expected, clrType);
+
+ // #2 Arrange & Act & Assert for nullable equals to true
+ clrType = _mapper.GetClrType(EdmModel, primitiveType, true, assembliesResolver: null);
+ if (expected.IsValueType)
+ {
+ Type generic = typeof(Nullable<>);
+ expected = generic.MakeGenericType(expected);
+ Assert.Same(expected, clrType);
+ }
+ else
+ {
+ Assert.Same(expected, clrType);
+ }
+ }
+
+ [Theory]
+ [InlineData(EdmPrimitiveTypeKind.Geography, typeof(Geography))]
+ [InlineData(EdmPrimitiveTypeKind.GeographyPoint, typeof(GeographyPoint))]
+ [InlineData(EdmPrimitiveTypeKind.GeographyLineString, typeof(GeographyLineString))]
+ [InlineData(EdmPrimitiveTypeKind.GeographyPolygon, typeof(GeographyPolygon))]
+ [InlineData(EdmPrimitiveTypeKind.GeographyCollection, typeof(GeographyCollection))]
+ [InlineData(EdmPrimitiveTypeKind.GeographyMultiLineString, typeof(GeographyMultiLineString))]
+ [InlineData(EdmPrimitiveTypeKind.GeographyMultiPoint, typeof(GeographyMultiPoint))]
+ [InlineData(EdmPrimitiveTypeKind.GeographyMultiPolygon, typeof(GeographyMultiPolygon))]
+ [InlineData(EdmPrimitiveTypeKind.Geometry, typeof(Geometry))]
+ [InlineData(EdmPrimitiveTypeKind.GeometryPoint, typeof(GeometryPoint))]
+ [InlineData(EdmPrimitiveTypeKind.GeometryLineString, typeof(GeometryLineString))]
+ [InlineData(EdmPrimitiveTypeKind.GeometryPolygon, typeof(GeometryPolygon))]
+ [InlineData(EdmPrimitiveTypeKind.GeometryCollection, typeof(GeometryCollection))]
+ [InlineData(EdmPrimitiveTypeKind.GeometryMultiLineString, typeof(GeometryMultiLineString))]
+ [InlineData(EdmPrimitiveTypeKind.GeometryMultiPoint, typeof(GeometryMultiPoint))]
+ [InlineData(EdmPrimitiveTypeKind.GeometryMultiPolygon, typeof(GeometryMultiPolygon))]
+ public void GetClrType_WorksAsExpected_ForSpatialPrimitive(EdmPrimitiveTypeKind kind, Type type)
+ {
+ // Arrange
+ IEdmPrimitiveType primitiveType = EdmCoreModel.Instance.GetPrimitiveType(kind);
+
+ // Act
+ Type clrType1 = _mapper.GetClrType(EdmModel, primitiveType, false, assembliesResolver: null);
+ Type clrType2 = _mapper.GetClrType(EdmModel, primitiveType, true, assembliesResolver: null);
+
+ // Assert
+ Assert.Same(clrType1, clrType2);
+ Assert.Same(type, clrType1);
+ }
+
+ [Theory]
+ [InlineData("NS.Address", typeof(MyAddress))] // use ClrTypeAnnotation
+ [InlineData("NS.CnAddress", typeof(CnMyAddress))]
+ [InlineData("Microsoft.AspNetCore.OData.Tests.Edm.MyCustomer", typeof(MyCustomer))] // use the full name match
+ public void GetClrType_WorksAsExpected_ForSchemaStrucutralType(string typeName, Type expected)
+ {
+ // Arrange
+ IEdmType edmType = EdmModel.FindType(typeName);
+ Assert.NotNull(edmType); // Guard
+
+ // #1. Act & Assert
+ Type clrType = _mapper.GetClrType(EdmModel, edmType, true, new AssemblyResolver());
+ Assert.Same(expected, clrType);
+
+ // #2. Act & Assert
+ clrType = _mapper.GetClrType(EdmModel, edmType, false, new AssemblyResolver());
+ Assert.Same(expected, clrType);
+ }
+
+ [Fact]
+ public void GetClrType_WorksAsExpected_ForSchemaEnumType()
+ {
+ // Arrange
+ IEdmType edmType = EdmModel.FindType("NS.Color");
+ Assert.NotNull(edmType); // Guard
+
+ // #1. Act & Assert
+ Type clrType = _mapper.GetClrType(EdmModel, edmType, true, null);
+ Assert.Same(typeof(MyColor?), clrType);
+
+ // #2. Act & Assert
+ clrType = _mapper.GetClrType(EdmModel, edmType, false, null);
+ Assert.Same(typeof(MyColor), clrType);
+ }
+
+ #endregion
+
+ #region GetEdmType
+ [Fact]
+ public void GetEdmType_ThrowsArgumentNull_ModelAndClrType()
+ {
+ // Arrange & Act
+ IEdmModel model = null;
+ ExceptionAssert.ThrowsArgumentNull(() => _mapper.GetEdmTypeReference(model, typeof(TypeNotInModel)), "edmModel");
+
+ model = new Mock().Object;
+ ExceptionAssert.ThrowsArgumentNull(() => _mapper.GetEdmTypeReference(model, null), "clrType");
+ }
+
+ [Fact]
+ public void GetEdmTypeReference_ReturnsNull_ForUnknownType()
+ {
+ // Arrange & Act & Assert
+ Assert.Null(_mapper.GetEdmTypeReference(EdmModel, typeof(TypeNotInModel)));
+ }
+
+ [Theory]
+ [InlineData(typeof(IEnumerable), "NS.BaseType")]
+ [InlineData(typeof(IEnumerable), "NS.Derived1Type")]
+ [InlineData(typeof(Derived2Type[]), "NS.Derived2Type")]
+ public void GetEdmTypeReference_ReturnsCollection_ForIEnumerableOfT(Type clrType, string typeName)
+ {
+ // Arrange & Act
+ IEdmType edmType = _mapper.GetEdmType(EdmModel, clrType);
+
+ // Assert
+ Assert.Equal(EdmTypeKind.Collection, edmType.TypeKind);
+ Assert.Equal(typeName, (edmType as IEdmCollectionType).ElementType.FullName());
+ }
+
+ [Theory]
+ [InlineData(typeof(string), "Edm.String")]
+ [InlineData(typeof(int?), "Edm.Int32")]
+ [InlineData(typeof(MyAddress), "NS.Address")]
+ [InlineData(typeof(CnMyAddress), "NS.CnAddress")]
+ [InlineData(typeof(MyCustomer), "Microsoft.AspNetCore.OData.Tests.Edm.MyCustomer")]
+ [InlineData(typeof(BaseType), "NS.BaseType")]
+ [InlineData(typeof(Derived1Type), "NS.Derived1Type")]
+ [InlineData(typeof(Derived2Type), "NS.Derived2Type")]
+ [InlineData(typeof(SubDerivedType), "NS.SubDerivedType")]
+ public void GetEdmTypeReference_WorksAsExpected_ForEdmType(Type clrType, string typeName)
+ {
+ // Arrange
+ IEdmType expectedEdmType = EdmModel.FindType(typeName);
+ Assert.NotNull(expectedEdmType); // Guard
+
+ // Arrange & Act
+ IEdmTypeReference edmTypeRef = _mapper.GetEdmTypeReference(EdmModel, clrType);
+ IEdmType edmType = _mapper.GetEdmType(EdmModel, clrType);
+
+ // Assert
+ Assert.NotNull(edmTypeRef);
+ Assert.Same(expectedEdmType, edmTypeRef.Definition);
+ Assert.Same(expectedEdmType, edmType);
+ Assert.True(edmTypeRef.IsNullable);
+ }
+
+ [Fact]
+ public void GetEdmTypeReference_WorksAsExpected_ForSchemaEnumType()
+ {
+ // Arrange
+ IEdmType expectedType = EdmModel.FindType("NS.Color");
+ Assert.NotNull(expectedType); // Guard
+
+ // #1. Act & Assert
+ IEdmTypeReference colorType = _mapper.GetEdmTypeReference(EdmModel, typeof(MyColor));
+ Assert.Same(expectedType, colorType.Definition);
+ Assert.False(colorType.IsNullable);
+
+ // #2. Act & Assert
+ colorType = _mapper.GetEdmTypeReference(EdmModel, typeof(MyColor?));
+ Assert.Same(expectedType, colorType.Definition);
+ Assert.True(colorType.IsNullable);
+ }
+ #endregion
+
+ [Theory]
+ [InlineData(typeof(MyCustomer), "MyCustomer")]
+ [InlineData(typeof(int), "Int32")]
+ [InlineData(typeof(IEnumerable), "IEnumerable_1OfInt32")]
+ [InlineData(typeof(IEnumerable>), "IEnumerable_1OfFunc_2OfInt32_String")]
+ [InlineData(typeof(List>), "List_1OfFunc_2OfInt32_String")]
+ public void EdmFullName(Type clrType, string expectedName)
+ {
+ // Arrange & Act & Assert
+ Assert.Equal(expectedName, clrType.EdmName());
+ }
+
+ private static IEdmModel GetEdmModel()
+ {
+ EdmModel model = new EdmModel();
+
+ // ComplexType: Address
+ EdmComplexType address = new EdmComplexType("NS", "Address");
+ address.AddStructuralProperty("City", EdmPrimitiveTypeKind.String);
+ model.AddElement(address);
+ model.SetAnnotationValue(address, new ClrTypeAnnotation(typeof(MyAddress)));
+
+ // ComplexType: CnAddress
+ var cnAddress = new EdmComplexType("NS", "CnAddress", address);
+ cnAddress.AddStructuralProperty("Zipcode", EdmPrimitiveTypeKind.String);
+ model.AddElement(cnAddress);
+ model.SetAnnotationValue(cnAddress, new ClrTypeAnnotation(typeof(CnMyAddress)));
+
+ // EnumType: Color
+ var color = new EdmEnumType("NS", "Color");
+ model.AddElement(color);
+ model.SetAnnotationValue(color, new ClrTypeAnnotation(typeof(MyColor)));
+
+ // EntityType: MyCustomer
+ var customer = new EdmEntityType("Microsoft.AspNetCore.OData.Tests.Edm", "MyCustomer");
+ model.AddElement(customer);
+
+ // Inheritance EntityType
+ var baseEntity = new EdmEntityType("NS", "BaseType");
+ var derived1Entity = new EdmEntityType("NS", "Derived1Type", baseEntity);
+ var derived2Entity = new EdmEntityType("NS", "Derived2Type", baseEntity);
+ var subDerivedEntity = new EdmEntityType("NS", "SubDerivedType", derived1Entity);
+ model.AddElements(new[] { baseEntity, derived1Entity, derived2Entity, subDerivedEntity });
+ model.SetAnnotationValue(baseEntity, new ClrTypeAnnotation(typeof(BaseType)));
+ model.SetAnnotationValue(derived1Entity, new ClrTypeAnnotation(typeof(Derived1Type)));
+ model.SetAnnotationValue(derived2Entity, new ClrTypeAnnotation(typeof(Derived2Type)));
+ model.SetAnnotationValue(subDerivedEntity, new ClrTypeAnnotation(typeof(SubDerivedType)));
+
+ return model;
+ }
+
+ public class MyAddress
+ {
+ public string City { get; set; }
+ }
+
+ public class CnMyAddress : MyAddress
+ {
+ public string Zipcode { get; set; }
+ }
+
+ public enum MyColor
+ {
+ Red
+ }
+
+ public class BaseType
+ { }
+
+ public class Derived1Type : BaseType
+ { }
+
+ public class Derived2Type : BaseType
+ { }
+
+ public class SubDerivedType : Derived1Type
+ { }
+
+ public class TypeNotInModel
+ { }
+
+ public class AssemblyResolver : IAssemblyResolver
+ {
+ public IEnumerable Assemblies
+ {
+ get
+ {
+ yield return typeof(AssemblyResolver).Assembly;
+ }
+ }
+ }
+ }
+
+ public class MyCustomer
+ { }
+}
diff --git a/test/Microsoft.AspNetCore.OData.Tests/Edm/EdmClrTypeMapExtensionsTests.cs b/test/Microsoft.AspNetCore.OData.Tests/Edm/EdmClrTypeMapExtensionsTests.cs
index da2d394d7..aedca1046 100644
--- a/test/Microsoft.AspNetCore.OData.Tests/Edm/EdmClrTypeMapExtensionsTests.cs
+++ b/test/Microsoft.AspNetCore.OData.Tests/Edm/EdmClrTypeMapExtensionsTests.cs
@@ -7,14 +7,11 @@
using System;
using System.Collections.Generic;
-using System.IO;
-using System.Reflection;
using System.Xml.Linq;
+using Microsoft.AspNetCore.OData.Abstracts;
using Microsoft.AspNetCore.OData.Edm;
-using Microsoft.AspNetCore.OData.Tests.Commons;
using Microsoft.OData.Edm;
using Microsoft.OData.ModelBuilder;
-using Microsoft.Spatial;
using Moq;
using Xunit;
@@ -22,108 +19,44 @@ namespace Microsoft.AspNetCore.OData.Tests.Edm
{
public class EdmClrTypeMapExtensionsTests
{
- private static IEdmModel EdmModel = GetEdmModel();
-
- #region PrimitiveType
- [Theory]
- [InlineData(typeof(string), "Edm.String", true)]
- [InlineData(typeof(bool), "Edm.Boolean", false)]
- [InlineData(typeof(bool?), "Edm.Boolean", true)]
- [InlineData(typeof(byte), "Edm.Byte", false)]
- [InlineData(typeof(byte?), "Edm.Byte", true)]
- [InlineData(typeof(decimal), "Edm.Decimal", false)]
- [InlineData(typeof(decimal?), "Edm.Decimal", true)]
- [InlineData(typeof(double), "Edm.Double", false)]
- [InlineData(typeof(double?), "Edm.Double", true)]
- [InlineData(typeof(Guid), "Edm.Guid", false)]
- [InlineData(typeof(Guid?), "Edm.Guid", true)]
- [InlineData(typeof(short), "Edm.Int16", false)]
- [InlineData(typeof(short?), "Edm.Int16", true)]
- [InlineData(typeof(int), "Edm.Int32", false)]
- [InlineData(typeof(int?), "Edm.Int32", true)]
- [InlineData(typeof(long), "Edm.Int64", false)]
- [InlineData(typeof(long?), "Edm.Int64", true)]
- [InlineData(typeof(sbyte), "Edm.SByte", false)]
- [InlineData(typeof(sbyte?), "Edm.SByte", true)]
- [InlineData(typeof(float), "Edm.Single", false)]
- [InlineData(typeof(float?), "Edm.Single", true)]
- [InlineData(typeof(DateTimeOffset), "Edm.DateTimeOffset", false)]
- [InlineData(typeof(DateTimeOffset?), "Edm.DateTimeOffset", true)]
- [InlineData(typeof(TimeSpan), "Edm.Duration", false)]
- [InlineData(typeof(TimeSpan?), "Edm.Duration", true)]
- [InlineData(typeof(Date), "Edm.Date", false)]
- [InlineData(typeof(Date?), "Edm.Date", true)]
- [InlineData(typeof(TimeOfDay), "Edm.TimeOfDay", false)]
- [InlineData(typeof(TimeOfDay?), "Edm.TimeOfDay", true)]
- [InlineData(typeof(byte[]), "Edm.Binary", true)]
- [InlineData(typeof(Stream), "Edm.Stream", true)]
- public void GetEdmPrimitiveTypeReferenceWorksAsExpectedForStandardPrimitive(Type clrType, string name, bool nullable)
+ [Fact]
+ public void GetEdmPrimitiveTypeReference_Calls_GetPrimitiveTypeOnMapper()
{
- // Arrange & Act
- IEdmPrimitiveTypeReference primitiveTypeReference = clrType.GetEdmPrimitiveTypeReference();
- IEdmPrimitiveType primitiveType = clrType.GetEdmPrimitiveType();
+ // Arrange
+ Type type = typeof(int);
+ Mock mapper = new Mock();
+ mapper.Setup(x => x.GetPrimitiveType(type)).Verifiable();
- // Assert
- Assert.NotNull(primitiveTypeReference);
- Assert.Same(primitiveTypeReference.Definition, primitiveType);
- Assert.Equal(name, primitiveTypeReference.FullName());
- Assert.Equal(nullable, primitiveTypeReference.IsNullable);
- }
+ EdmModel model = new EdmModel();
+ model.SetTypeMapper(mapper.Object);
- [Theory]
- [InlineData(typeof(XElement), "Edm.String", true)]
- [InlineData(typeof(ushort), "Edm.Int32", false)]
- [InlineData(typeof(ushort?), "Edm.Int32", true)]
- [InlineData(typeof(uint), "Edm.Int64", false)]
- [InlineData(typeof(uint?), "Edm.Int64", true)]
- [InlineData(typeof(ulong), "Edm.Int64", false)]
- [InlineData(typeof(ulong?), "Edm.Int64", true)]
- [InlineData(typeof(char[]), "Edm.String", true)]
- [InlineData(typeof(char), "Edm.String", false)]
- [InlineData(typeof(char?), "Edm.String", true)]
- [InlineData(typeof(DateTime), "Edm.DateTimeOffset", false)]
- [InlineData(typeof(DateTime?), "Edm.DateTimeOffset", true)]
- public void GetEdmPrimitiveTypeReferenceWorksAsExpectedForNonStandardPrimitive(Type clrType, string name, bool nullable)
- {
- // Arrange & Act
- IEdmPrimitiveTypeReference primitiveTypeReference = clrType.GetEdmPrimitiveTypeReference();
- IEdmPrimitiveType primitiveType = clrType.GetEdmPrimitiveType();
+ // Act
+ model.GetEdmPrimitiveTypeReference(type);
// Assert
- Assert.NotNull(primitiveTypeReference);
- Assert.Same(primitiveTypeReference.Definition, primitiveType);
- Assert.Equal(name, primitiveTypeReference.FullName());
- Assert.Equal(nullable, primitiveTypeReference.IsNullable);
+ mapper.Verify();
}
- [Theory]
- [InlineData(typeof(Geography), "Edm.Geography")]
- [InlineData(typeof(GeographyPoint), "Edm.GeographyPoint")]
- [InlineData(typeof(GeographyLineString), "Edm.GeographyLineString")]
- [InlineData(typeof(GeographyPolygon), "Edm.GeographyPolygon")]
- [InlineData(typeof(GeographyCollection), "Edm.GeographyCollection")]
- [InlineData(typeof(GeographyMultiLineString), "Edm.GeographyMultiLineString")]
- [InlineData(typeof(GeographyMultiPoint), "Edm.GeographyMultiPoint")]
- [InlineData(typeof(GeographyMultiPolygon), "Edm.GeographyMultiPolygon")]
- [InlineData(typeof(Geometry), "Edm.Geometry")]
- [InlineData(typeof(GeometryPoint), "Edm.GeometryPoint")]
- [InlineData(typeof(GeometryLineString), "Edm.GeometryLineString")]
- [InlineData(typeof(GeometryPolygon), "Edm.GeometryPolygon")]
- [InlineData(typeof(GeometryCollection), "Edm.GeometryCollection")]
- [InlineData(typeof(GeometryMultiLineString), "Edm.GeometryMultiLineString")]
- [InlineData(typeof(GeometryMultiPoint), "Edm.GeometryMultiPoint")]
- [InlineData(typeof(GeometryMultiPolygon), "Edm.GeometryMultiPolygon")]
- public void GetEdmTypeWorksAsExpectedForSpatialPrimitive(Type clrType, string name)
+ [Fact]
+ public void GetClrPrimitiveType_Calls_GetPrimitiveTypeOnMapper()
{
- // Arrange & Act
- IEdmPrimitiveTypeReference primitiveTypeReference = clrType.GetEdmPrimitiveTypeReference();
- IEdmPrimitiveType primitiveType = clrType.GetEdmPrimitiveType();
+ // Arrange
+ Mock primitiveType = new Mock();
+ Mock edmType = new Mock();
+ edmType.Setup(x => x.Definition).Returns(primitiveType.Object);
+ edmType.Setup(x => x.IsNullable).Returns(true);
+
+ Mock mapper = new Mock();
+ mapper.Setup(x => x.GetPrimitiveType(edmType.Object.PrimitiveDefinition(), edmType.Object.IsNullable)).Verifiable();
+
+ EdmModel model = new EdmModel();
+ model.SetTypeMapper(mapper.Object);
+
+ // Act
+ model.GetClrPrimitiveType(edmType.Object);
// Assert
- Assert.NotNull(primitiveTypeReference);
- Assert.Same(primitiveTypeReference.Definition, primitiveType);
- Assert.Equal(name, primitiveTypeReference.FullName());
- Assert.True(primitiveTypeReference.IsNullable);
+ mapper.Verify();
}
[Theory]
@@ -131,7 +64,6 @@ public void GetEdmTypeWorksAsExpectedForSpatialPrimitive(Type clrType, string na
[InlineData(typeof(int), typeof(int), false)]
[InlineData(typeof(int?), typeof(int?), false)]
[InlineData(typeof(object), typeof(object), false)]
- [InlineData(typeof(MyAddress), typeof(MyAddress), false)]
// non-standard primitive types
[InlineData(typeof(XElement), typeof(string), true)]
[InlineData(typeof(ushort), typeof(int), true)]
@@ -145,223 +77,138 @@ public void GetEdmTypeWorksAsExpectedForSpatialPrimitive(Type clrType, string na
[InlineData(typeof(char?), typeof(string), true)]
[InlineData(typeof(DateTime), typeof(DateTimeOffset), true)]
[InlineData(typeof(DateTime?), typeof(DateTimeOffset?), true)]
- public void IsNonstandardEdmPrimitiveWorksAsExpectedForNonstandardType(Type clrType, Type expectType, bool isNonstandard)
+ public void IsNonstandardEdmPrimitive_WorksAsExpected_ForNonstandardType(Type clrType, Type expectType, bool isNonstandard)
{
- // Arrange & Act
- Type actual = clrType.IsNonstandardEdmPrimitive(out bool isNonstandardEdmPrimtive);
+ // Arrange
+ EdmModel model = new EdmModel();
+ model.SetTypeMapper(DefaultODataTypeMapper.Default);
+
+ // Act
+ Type actual = model.IsNonstandardEdmPrimitive(clrType, out bool isNonstandardEdmPrimtive);
// Assert
Assert.Equal(expectType, actual);
Assert.Equal(isNonstandard, isNonstandardEdmPrimtive);
}
- #endregion
-
- #region GetClrType
[Fact]
- public void GetClrType_ThrowsArgumentNull_EdmType()
+ public void GetEdmTypeReference_Calls_GetEdmTypeReferenceOnMapper()
{
- // Arrange & Act
- IAssemblyResolver resolver = new Mock().Object;
- IEdmModel model = new Mock().Object;
- ExceptionAssert.ThrowsArgumentNull(() => model.GetClrType((IEdmTypeReference)null, resolver), "edmTypeReference");
+ // Arrange
+ Type type = typeof(int);
+ EdmModel model = new EdmModel();
- ExceptionAssert.ThrowsArgumentNull(() => model.GetClrType((IEdmType)null, resolver), "edmType");
- }
+ Mock mapper = new Mock();
+ mapper.Setup(x => x.GetEdmTypeReference(model, type)).Verifiable();
+ model.SetTypeMapper(mapper.Object);
- [Theory]
- [InlineData(EdmPrimitiveTypeKind.String, typeof(string))]
- [InlineData(EdmPrimitiveTypeKind.Boolean, typeof(bool))]
- [InlineData(EdmPrimitiveTypeKind.Byte, typeof(byte))]
- [InlineData(EdmPrimitiveTypeKind.Decimal, typeof(decimal))]
- [InlineData(EdmPrimitiveTypeKind.Double, typeof(double))]
- [InlineData(EdmPrimitiveTypeKind.Guid, typeof(Guid))]
- [InlineData(EdmPrimitiveTypeKind.Int16, typeof(short))]
- [InlineData(EdmPrimitiveTypeKind.Int32, typeof(int))]
- [InlineData(EdmPrimitiveTypeKind.Int64, typeof(long))]
- [InlineData(EdmPrimitiveTypeKind.SByte, typeof(sbyte))]
- [InlineData(EdmPrimitiveTypeKind.Single, typeof(float))]
- [InlineData(EdmPrimitiveTypeKind.Binary, typeof(byte[]))]
- [InlineData(EdmPrimitiveTypeKind.Stream, typeof(Stream))]
- [InlineData(EdmPrimitiveTypeKind.DateTimeOffset, typeof(DateTimeOffset))]
- [InlineData(EdmPrimitiveTypeKind.Duration, typeof(TimeSpan))]
- [InlineData(EdmPrimitiveTypeKind.Date, typeof(Date))]
- [InlineData(EdmPrimitiveTypeKind.TimeOfDay, typeof(TimeOfDay))]
- public void GetClrTypeWorksAsExpectedForStandardPrimitive(EdmPrimitiveTypeKind kind, Type expected)
- {
- // #1 Arrange & Act & Assert for nullable equals to false
- IEdmPrimitiveTypeReference primitiveType = EdmCoreModel.Instance.GetPrimitive(kind, false);
- Type clrType = EdmModel.GetClrType(primitiveType);
- Assert.Equal(expected, clrType);
-
- // #2 Arrange & Act & Assert for nullable equals to true
- primitiveType = EdmCoreModel.Instance.GetPrimitive(kind, true);
- clrType = EdmModel.GetClrType(primitiveType);
- if (expected.IsValueType)
- {
- Type generic = typeof(Nullable<>);
- expected = generic.MakeGenericType(expected);
- Assert.Same(expected, clrType);
- }
- else
- {
- Assert.Same(expected, clrType);
- }
+ // Act
+ model.GetEdmTypeReference(type);
+
+ // Assert
+ mapper.Verify();
}
- [Theory]
- [InlineData(EdmPrimitiveTypeKind.Geography, typeof(Geography))]
- [InlineData(EdmPrimitiveTypeKind.GeographyPoint, typeof(GeographyPoint))]
- [InlineData(EdmPrimitiveTypeKind.GeographyLineString, typeof(GeographyLineString))]
- [InlineData(EdmPrimitiveTypeKind.GeographyPolygon, typeof(GeographyPolygon))]
- [InlineData(EdmPrimitiveTypeKind.GeographyCollection, typeof(GeographyCollection))]
- [InlineData(EdmPrimitiveTypeKind.GeographyMultiLineString, typeof(GeographyMultiLineString))]
- [InlineData(EdmPrimitiveTypeKind.GeographyMultiPoint, typeof(GeographyMultiPoint))]
- [InlineData(EdmPrimitiveTypeKind.GeographyMultiPolygon, typeof(GeographyMultiPolygon))]
- [InlineData(EdmPrimitiveTypeKind.Geometry, typeof(Geometry))]
- [InlineData(EdmPrimitiveTypeKind.GeometryPoint, typeof(GeometryPoint))]
- [InlineData(EdmPrimitiveTypeKind.GeometryLineString, typeof(GeometryLineString))]
- [InlineData(EdmPrimitiveTypeKind.GeometryPolygon, typeof(GeometryPolygon))]
- [InlineData(EdmPrimitiveTypeKind.GeometryCollection, typeof(GeometryCollection))]
- [InlineData(EdmPrimitiveTypeKind.GeometryMultiLineString, typeof(GeometryMultiLineString))]
- [InlineData(EdmPrimitiveTypeKind.GeometryMultiPoint, typeof(GeometryMultiPoint))]
- [InlineData(EdmPrimitiveTypeKind.GeometryMultiPolygon, typeof(GeometryMultiPolygon))]
- public void GetClrTypeWorksAsExpectedForSpatialPrimitive(EdmPrimitiveTypeKind kind, Type type)
+ [Fact]
+ public void GetEdmType_Calls_GetEdmTypeReferenceOnMapper()
{
// Arrange
- IEdmPrimitiveTypeReference primitiveType1 = EdmCoreModel.Instance.GetPrimitive(kind, true);
- IEdmPrimitiveTypeReference primitiveType2 = EdmCoreModel.Instance.GetPrimitive(kind, false);
+ Type type = typeof(int);
+ EdmModel model = new EdmModel();
+
+ Mock mapper = new Mock();
+ mapper.Setup(x => x.GetEdmTypeReference(model, type)).Verifiable();
+ model.SetTypeMapper(mapper.Object);
// Act
- Type clrType1 = EdmModel.GetClrType(primitiveType1);
- Type clrType2 = EdmModel.GetClrType(primitiveType2);
+ model.GetEdmType(type);
// Assert
- Assert.Same(clrType1, clrType2);
- Assert.Same(type, clrType1);
- }
-
- [Theory]
- [InlineData("NS.Address", typeof(MyAddress))] // use ClrTypeAnnotation
- [InlineData("NS.CnAddress", typeof(CnMyAddress))]
- [InlineData("Microsoft.AspNetCore.OData.Tests.Edm.MyCustomer", typeof(MyCustomer))] // use the full name match
- public void GetClrTypeWorksAsExpectedForSchemaStrucutralType(string typeName, Type expected)
- {
- // Arrange
- IEdmType edmType = EdmModel.FindType(typeName);
- Assert.NotNull(edmType); // Guard
-
- // #1. Act & Assert
- IEdmTypeReference edmTypeReference = edmType.ToEdmTypeReference(true);
- Type clrType = EdmModel.GetClrType(edmTypeReference, new AssemblyResolver());
- Assert.Same(expected, clrType);
-
- // #2. Act & Assert
- edmTypeReference = edmType.ToEdmTypeReference(false);
- clrType = EdmModel.GetClrType(edmTypeReference);
- Assert.Same(expected, clrType);
+ mapper.Verify();
}
[Fact]
- public void GetClrTypeWorksAsExpectedForSchemaEnumType()
+ public void GetClrType_Calls_GetClrTypeOnMapper()
{
// Arrange
- IEdmType edmType = EdmModel.FindType("NS.Color");
- Assert.NotNull(edmType); // Guard
-
- // #1. Act & Assert
- IEdmTypeReference edmTypeReference = edmType.ToEdmTypeReference(true);
- Type clrType = EdmModel.GetClrType(edmTypeReference);
- Assert.Same(typeof(MyColor?), clrType);
-
- // #2. Act & Assert
- edmTypeReference = edmType.ToEdmTypeReference(false);
- clrType = EdmModel.GetClrType(edmTypeReference);
- Assert.Same(typeof(MyColor), clrType);
- }
+ Mock edmType = new Mock();
+ Mock edmTypeRef = new Mock();
+ edmTypeRef.Setup(x => x.Definition).Returns(edmType.Object);
+ edmTypeRef.Setup(x => x.IsNullable).Returns(true);
- #endregion
+ EdmModel model = new EdmModel();
- #region GetEdmType
+ Mock mapper = new Mock();
+ mapper.Setup(x => x.GetClrType(model, edmType.Object, true, AssemblyResolverHelper.Default)).Verifiable();
+ model.SetTypeMapper(mapper.Object);
- [Fact]
- public void GetEdmType_ThrowsArgumentNull_ModelAndClrType()
- {
- // Arrange & Act
- IEdmModel model = null;
- ExceptionAssert.ThrowsArgumentNull(() => model.GetEdmType(typeof(int)), "edmModel");
+ // Act
+ model.GetClrType(edmTypeRef.Object);
- model = new Mock().Object;
- ExceptionAssert.ThrowsArgumentNull(() => model.GetEdmType(null), "clrType");
+ // Assert
+ mapper.Verify();
}
[Fact]
- public void GetEdmTypeReferenceReturnsNullForUnknownType()
+ public void GetClrTypeWithResolver_Calls_GetClrTypeOnMapper()
{
- // Arrange & Act & Assert
- Assert.Null(EdmModel.GetEdmTypeReference(typeof(TypeNotInModel)));
- Assert.Null(EdmModel.GetEdmType(typeof(TypeNotInModel)));
- }
+ // Arrange
+ Mock resolver = new Mock();
+ Mock edmType = new Mock();
+ Mock edmTypeRef = new Mock();
+ edmTypeRef.Setup(x => x.Definition).Returns(edmType.Object);
+ edmTypeRef.Setup(x => x.IsNullable).Returns(true);
- [Theory]
- [InlineData(typeof(IEnumerable), "NS.BaseType")]
- [InlineData(typeof(IEnumerable), "NS.Derived1Type")]
- [InlineData(typeof(Derived2Type[]), "NS.Derived2Type")]
- public void GetEdmTypeReferenceReturnsCollectionForIEnumerableOfT(Type clrType, string typeName)
- {
- // Arrange & Act
- IEdmType edmType = EdmModel.GetEdmType(clrType);
+ EdmModel model = new EdmModel();
+
+ Mock mapper = new Mock();
+ mapper.Setup(x => x.GetClrType(model, edmType.Object, true, resolver.Object)).Verifiable();
+ model.SetTypeMapper(mapper.Object);
+
+ // Act
+ model.GetClrType(edmTypeRef.Object, resolver.Object);
// Assert
- Assert.Equal(EdmTypeKind.Collection, edmType.TypeKind);
- Assert.Equal(typeName, (edmType as IEdmCollectionType).ElementType.FullName());
+ mapper.Verify();
}
- [Theory]
- [InlineData(typeof(string), "Edm.String")]
- [InlineData(typeof(int?), "Edm.Int32")]
- [InlineData(typeof(MyAddress), "NS.Address")]
- [InlineData(typeof(CnMyAddress), "NS.CnAddress")]
- [InlineData(typeof(MyCustomer), "Microsoft.AspNetCore.OData.Tests.Edm.MyCustomer")]
- [InlineData(typeof(BaseType), "NS.BaseType")]
- [InlineData(typeof(Derived1Type), "NS.Derived1Type")]
- [InlineData(typeof(Derived2Type), "NS.Derived2Type")]
- [InlineData(typeof(SubDerivedType), "NS.SubDerivedType")]
- public void GetEdmTypeReferenceWorksAsExpectedForEdmType(Type clrType, string typeName)
+ [Fact]
+ public void GetClrTypeUsingEdmType_Calls_GetClrTypeOnMapper()
{
// Arrange
- IEdmType expectedEdmType = EdmModel.FindType(typeName);
- Assert.NotNull(expectedEdmType); // Guard
+ Mock edmType = new Mock();
+
+ EdmModel model = new EdmModel();
+ Mock mapper = new Mock();
+ mapper.Setup(x => x.GetClrType(model, edmType.Object, true, AssemblyResolverHelper.Default)).Verifiable();
+ model.SetTypeMapper(mapper.Object);
- // Arrange & Act
- IEdmTypeReference edmTypeRef = EdmModel.GetEdmTypeReference(clrType);
- IEdmType edmType = EdmModel.GetEdmType(clrType);
+ // Act
+ model.GetClrType(edmType.Object);
// Assert
- Assert.NotNull(edmTypeRef);
- Assert.Same(expectedEdmType, edmTypeRef.Definition);
- Assert.Same(expectedEdmType, edmType);
- Assert.True(edmTypeRef.IsNullable);
+ mapper.Verify();
}
[Fact]
- public void GetEdmTypeWorksAsExpectedForSchemaEnumType()
+ public void GetClrTypeUsingEdmTypeWithResolver_Calls_GetClrTypeOnMapper()
{
// Arrange
- IEdmType expectedType = EdmModel.FindType("NS.Color");
- Assert.NotNull(expectedType); // Guard
-
- // #1. Act & Assert
- IEdmTypeReference colorType = EdmModel.GetEdmTypeReference(typeof(MyColor));
- Assert.Same(expectedType, colorType.Definition);
- Assert.False(colorType.IsNullable);
-
- // #2. Act & Assert
- colorType = EdmModel.GetEdmTypeReference(typeof(MyColor?));
- Assert.Same(expectedType, colorType.Definition);
- Assert.True(colorType.IsNullable);
+ Mock resolver = new Mock();
+ Mock edmType = new Mock();
+
+ EdmModel model = new EdmModel();
+
+ Mock mapper = new Mock();
+ mapper.Setup(x => x.GetClrType(model, edmType.Object, true, resolver.Object)).Verifiable();
+ model.SetTypeMapper(mapper.Object);
+
+ // Act
+ model.GetClrType(edmType.Object, resolver.Object);
+
+ // Assert
+ mapper.Verify();
}
- #endregion
[Theory]
[InlineData(typeof(MyCustomer), "MyCustomer")]
@@ -374,82 +221,5 @@ public void EdmFullName(Type clrType, string expectedName)
// Arrange & Act & Assert
Assert.Equal(expectedName, clrType.EdmName());
}
-
- private static IEdmModel GetEdmModel()
- {
- EdmModel model = new EdmModel();
- EdmComplexType address = new EdmComplexType("NS", "Address");
- address.AddStructuralProperty("City", EdmPrimitiveTypeKind.String);
- model.AddElement(address);
- model.SetAnnotationValue(address, new ClrTypeAnnotation(typeof(MyAddress)));
- var cnAddress = new EdmComplexType("NS", "CnAddress", address);
- cnAddress.AddStructuralProperty("Zipcode", EdmPrimitiveTypeKind.String);
- model.AddElement(cnAddress);
- model.SetAnnotationValue(cnAddress, new ClrTypeAnnotation(typeof(CnMyAddress)));
-
- var color = new EdmEnumType("NS", "Color");
- model.AddElement(color);
- model.SetAnnotationValue(color, new ClrTypeAnnotation(typeof(MyColor)));
-
- var customer = new EdmEntityType("Microsoft.AspNetCore.OData.Tests.Edm", "MyCustomer");
- model.AddElement(customer);
-
- // Inheritance
- var baseEntity = new EdmEntityType("NS", "BaseType");
- var derived1Entity = new EdmEntityType("NS", "Derived1Type", baseEntity);
- var derived2Entity = new EdmEntityType("NS", "Derived2Type", baseEntity);
- var subDerivedEntity = new EdmEntityType("NS", "SubDerivedType", derived1Entity);
- model.AddElements(new[] { baseEntity, derived1Entity, derived2Entity, subDerivedEntity });
- model.SetAnnotationValue(baseEntity, new ClrTypeAnnotation(typeof(BaseType)));
- model.SetAnnotationValue(derived1Entity, new ClrTypeAnnotation(typeof(Derived1Type)));
- model.SetAnnotationValue(derived2Entity, new ClrTypeAnnotation(typeof(Derived2Type)));
- model.SetAnnotationValue(subDerivedEntity, new ClrTypeAnnotation(typeof(SubDerivedType)));
-
- return model;
- }
-
- public class MyAddress
- {
- public string City { get; set; }
- }
-
- public class CnMyAddress : MyAddress
- {
- public string Zipcode { get; set; }
- }
-
- public enum MyColor
- {
- Red
- }
-
- public class BaseType
- { }
-
- public class Derived1Type : BaseType
- { }
-
- public class Derived2Type : BaseType
- { }
-
- public class SubDerivedType : Derived1Type
- { }
-
- public class TypeNotInModel
- { }
-
- public class AssemblyResolver : IAssemblyResolver
- {
- public IEnumerable Assemblies
- {
- get
- {
- yield return typeof(AssemblyResolver).Assembly;
- }
- }
- }
}
-
- public class MyCustomer
- { }
}
diff --git a/test/Microsoft.AspNetCore.OData.Tests/Edm/EdmModelAnnotationExtensionsTests.cs b/test/Microsoft.AspNetCore.OData.Tests/Edm/EdmModelAnnotationExtensionsTests.cs
index 88fea63b3..7fec55a8a 100644
--- a/test/Microsoft.AspNetCore.OData.Tests/Edm/EdmModelAnnotationExtensionsTests.cs
+++ b/test/Microsoft.AspNetCore.OData.Tests/Edm/EdmModelAnnotationExtensionsTests.cs
@@ -204,6 +204,48 @@ public void GetAndSetModelName_RoundTrip()
Assert.Equal(testName, name);
}
+ [Fact]
+ public void GetTypeMapper_ReturnsDefaultTypeMapper_IfNullModelOrWithoutTypeMapper()
+ {
+ // Arrange & Act & Assert
+ IEdmModel model = null;
+ Assert.IsType(model.GetTypeMapper());
+
+ // Arrange & Act & Assert
+ model = EdmCoreModel.Instance;
+ Assert.IsType(model.GetTypeMapper());
+
+ // Arrange & Act & Assert
+ model = new EdmModel();
+ Assert.IsType(model.GetTypeMapper());
+ }
+
+ [Fact]
+ public void SetTypeMapper_ThrowsArugmentNull_Model()
+ {
+ // Arrange & Act & Assert
+ IEdmModel model = null;
+ ExceptionAssert.ThrowsArgumentNull(() => model.SetTypeMapper(null), "model");
+
+ model = new Mock().Object;
+ ExceptionAssert.ThrowsArgumentNull(() => model.SetTypeMapper(null), "mapper");
+ }
+
+ [Fact]
+ public void GetAndSetTypeMapper_RoundTrip()
+ {
+ // Arrange
+ IODataTypeMapper mapper = new Mock().Object;
+ IEdmModel model = new EdmModel();
+
+ // Act
+ model.SetTypeMapper(mapper);
+ IODataTypeMapper actual = model.GetTypeMapper();
+
+ // Assert
+ Assert.Same(mapper, actual);
+ }
+
[Fact]
public void GetAlternateKeys_ThrowsArugmentNull_ForInputParameters()
{
diff --git a/test/Microsoft.AspNetCore.OData.Tests/Edm/IODataTypeMapperExtensionsTests.cs b/test/Microsoft.AspNetCore.OData.Tests/Edm/IODataTypeMapperExtensionsTests.cs
new file mode 100644
index 000000000..a9f4ced7c
--- /dev/null
+++ b/test/Microsoft.AspNetCore.OData.Tests/Edm/IODataTypeMapperExtensionsTests.cs
@@ -0,0 +1,130 @@
+//-----------------------------------------------------------------------------
+//
+// Copyright (c) .NET Foundation and Contributors. All rights reserved.
+// See License.txt in the project root for license information.
+//
+//------------------------------------------------------------------------------
+
+using System;
+using Microsoft.AspNetCore.OData.Abstracts;
+using Microsoft.AspNetCore.OData.Edm;
+using Microsoft.AspNetCore.OData.Tests.Commons;
+using Microsoft.OData.Edm;
+using Microsoft.OData.ModelBuilder;
+using Moq;
+using Xunit;
+
+namespace Microsoft.AspNetCore.OData.Tests.Edm
+{
+ public class IODataTypeMapperExtensionsTests
+ {
+ [Fact]
+ public void GetPrimitiveType_ThrowsArgumentNull_ForInputParameters()
+ {
+ // Arrange & Act & Assert
+ IODataTypeMapper mapper = null;
+ ExceptionAssert.ThrowsArgumentNull(() => mapper.GetPrimitiveType(primitiveType: null), "mapper");
+
+ // Arrange & Act & Assert
+ mapper = new Mock().Object;
+ ExceptionAssert.ThrowsArgumentNull(() => mapper.GetPrimitiveType(primitiveType: null), "primitiveType");
+ }
+
+ [Fact]
+ public void GetPrimitiveType_Calls_GetPrimitiveTypeOnInterface()
+ {
+ // Arrange
+ Mock primitive = new Mock();
+ Mock primitiveRef = new Mock();
+ primitiveRef.Setup(x => x.Definition).Returns(primitive.Object);
+ primitiveRef.SetupGet(x => x.IsNullable).Returns(false);
+
+ Mock mapper = new Mock();
+ mapper.Setup(s => s.GetPrimitiveType(primitive.Object, false)).Verifiable();
+
+ // Act
+ mapper.Object.GetPrimitiveType(primitiveRef.Object);
+
+ // Assert
+ mapper.Verify();
+ }
+
+ [Fact]
+ public void GetEdmType_ThrowsArgumentNull_ForInputParameters()
+ {
+ // Arrange & Act & Assert
+ IODataTypeMapper mapper = null;
+ ExceptionAssert.ThrowsArgumentNull(() => mapper.GetEdmType(null, null), "mapper");
+ }
+
+ [Fact]
+ public void GetEdmType_Calls_GetEdmTypeReferenceOnInterface()
+ {
+ // Arrange
+ Mock model = new Mock();
+ Type type = typeof(int);
+
+ Mock mapper = new Mock();
+ mapper.Setup(s => s.GetEdmTypeReference(model.Object, type)).Verifiable();
+
+ // Act
+ mapper.Object.GetEdmType(model.Object, type);
+
+ // Assert
+ mapper.Verify();
+ }
+
+ [Fact]
+ public void GetClrType_ThrowsArgumentNull_ForInputParameters()
+ {
+ // Arrange & Act & Assert
+ IODataTypeMapper mapper = null;
+ ExceptionAssert.ThrowsArgumentNull(() => mapper.GetClrType(null, null), "mapper");
+
+ // Arrange & Act & Assert
+ mapper = new Mock().Object;
+ ExceptionAssert.ThrowsArgumentNull(() => mapper.GetClrType(null, null), "edmType");
+ }
+
+ [Fact]
+ public void GetClrType_Calls_GetClrTypeOnInterface()
+ {
+ // Arrange
+ Mock model = new Mock();
+ Mock primitive = new Mock();
+ Mock primitiveRef = new Mock();
+ primitiveRef.Setup(x => x.Definition).Returns(primitive.Object);
+ primitiveRef.SetupGet(x => x.IsNullable).Returns(false);
+
+ Mock mapper = new Mock();
+ mapper.Setup(s => s.GetClrType(model.Object, primitive.Object, false, AssemblyResolverHelper.Default)).Verifiable();
+
+ // Act
+ mapper.Object.GetClrType(model.Object, primitiveRef.Object);
+
+ // Assert
+ mapper.Verify();
+ }
+
+ [Fact]
+ public void GetClrTypeWithAssemblyResolver_Calls_GetClrTypeOnInterface()
+ {
+ // Arrange
+ Mock resolver = new Mock();
+ Mock model = new Mock