Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
24 changes: 24 additions & 0 deletions src/Microsoft.AspNetCore.OData/Common/TypeHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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);
}

/// <summary>
/// Return the collection element type.
/// </summary>
Expand Down
438 changes: 438 additions & 0 deletions src/Microsoft.AspNetCore.OData/Edm/DefaultODataTypeMapper.cs

Large diffs are not rendered by default.

363 changes: 37 additions & 326 deletions src/Microsoft.AspNetCore.OData/Edm/EdmClrTypeMapExtensions.cs

Large diffs are not rendered by default.

42 changes: 42 additions & 0 deletions src/Microsoft.AspNetCore.OData/Edm/EdmModelAnnotationExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,48 @@ public static void SetModelName(this IEdmModel model, string name)
model.SetAnnotationValue(model, new ModelNameAnnotation(name));
}

/// <summary>
/// Gets the OData type mapping provider from the model.
/// </summary>
/// <param name="model">The Edm model.</param>
/// <returns>The <see cref="IODataTypeMapper"/>.</returns>
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<IODataTypeMapper>(model);
if (provider == null)
{
return DefaultODataTypeMapper.Default;
}

return provider;
}

/// <summary>
/// Sets the OData type mapping provider to the model.
/// </summary>
/// <param name="model">The Edm model.</param>
/// <param name="mapper">The given mapper.</param>
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);
}

/// <summary>
/// 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.
Expand Down
52 changes: 52 additions & 0 deletions src/Microsoft.AspNetCore.OData/Edm/IODataTypeMapper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
//-----------------------------------------------------------------------------
// <copyright file="IODataTypeMapper.cs" company=".NET Foundation">
// Copyright (c) .NET Foundation and Contributors. All rights reserved.
// See License.txt in the project root for license information.
// </copyright>
//------------------------------------------------------------------------------

using System;
using Microsoft.OData.Edm;
using Microsoft.OData.ModelBuilder;

namespace Microsoft.AspNetCore.OData.Edm
{
/// <summary>
/// Provides the mapping between CLR type and Edm type.
/// </summary>
public interface IODataTypeMapper
{
/// <summary>
/// Gets the corresponding Edm primitive type <see cref="IEdmPrimitiveTypeReference"/> for a given <see cref="Type"/>.
/// </summary>
/// <param name="clrType">The given CLR type.</param>
/// <returns>Null or the Edm primitive type.</returns>
IEdmPrimitiveTypeReference GetPrimitiveType(Type clrType);

/// <summary>
/// Gets the corresponding <see cref="Type"/> for a given Edm primitive type <see cref="IEdmPrimitiveType"/>.
/// </summary>
/// <param name="primitiveType">The given Edm primitive type.</param>
/// <param name="nullable">The nullable or not.</param>
/// <returns>Null or the CLR type.</returns>
Type GetPrimitiveType(IEdmPrimitiveType primitiveType, bool nullable);

/// <summary>
/// Gets the corresponding Edm type <see cref="IEdmTypeReference"/> for the given CLR type <see cref="Type"/>.
/// </summary>
/// <param name="edmModel">The given Edm model.</param>
/// <param name="clrType">The given CLR type.</param>
/// <returns>Null or the corresponding Edm type reference.</returns>
IEdmTypeReference GetEdmTypeReference(IEdmModel edmModel, Type clrType);

/// <summary>
/// Gets the corresponding <see cref="Type"/> for a given Edm type <see cref="IEdmType"/>.
/// </summary>
/// <param name="edmModel">The given Edm model.</param>
/// <param name="edmType">The given Edm type.</param>
/// <param name="nullable">The nullable or not.</param>
/// <param name="assembliesResolver">The assembly resolver.</param>
/// <returns>Null or the CLR type.</returns>
Type GetClrType(IEdmModel edmModel, IEdmType edmType, bool nullable, IAssemblyResolver assembliesResolver);
}
}
93 changes: 93 additions & 0 deletions src/Microsoft.AspNetCore.OData/Edm/IODataTypeMapperExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
//-----------------------------------------------------------------------------
// <copyright file="IODataTypeMapperExtensions.cs" company=".NET Foundation">
// Copyright (c) .NET Foundation and Contributors. All rights reserved.
// See License.txt in the project root for license information.
// </copyright>
//------------------------------------------------------------------------------

using System;
using Microsoft.AspNetCore.OData.Abstracts;
using Microsoft.OData.Edm;
using Microsoft.OData.ModelBuilder;

namespace Microsoft.AspNetCore.OData.Edm
{
/// <summary>
/// Extension methods for <see cref="IODataTypeMapper"/>.
/// </summary>
public static class IODataTypeMapperExtensions
{
/// <summary>
/// Gets the corresponding <see cref="Type"/> for a given Edm primitive type <see cref="IEdmPrimitiveTypeReference"/>.
/// </summary>
/// <param name="mapper">The type mapper.</param>
/// <param name="primitiveType">The Edm primitive type reference.</param>
/// <returns>Null or the CLR type.</returns>
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);
}

/// <summary>
/// Gets the corresponding Edm type <see cref="IEdmType"/> for the given CLR type <see cref="Type"/>.
/// </summary>
/// <param name="mapper">The type mapper.</param>
/// <param name="edmModel">The given Edm model.</param>
/// <param name="clrType">The given CLR type.</param>
/// <returns>Null or the corresponding Edm type.</returns>
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;
}

/// <summary>
/// Gets the corresponding <see cref="Type"/> for a given Edm type <see cref="IEdmTypeReference"/>.
/// </summary>
/// <param name="mapper">The type mapper.</param>
/// <param name="edmModel">The Edm model.</param>
/// <param name="edmType">The Edm type reference.</param>
/// <returns>Null or the CLR type.</returns>
public static Type GetClrType(this IODataTypeMapper mapper, IEdmModel edmModel, IEdmTypeReference edmType)
{
return mapper.GetClrType(edmModel, edmType, AssemblyResolverHelper.Default);
}

/// <summary>
/// Gets the corresponding <see cref="Type"/> for a given Edm type <see cref="IEdmTypeReference"/>.
/// </summary>
/// <param name="mapper">The type mapper.</param>
/// <param name="edmModel">The Edm model.</param>
/// <param name="edmType">The Edm type.</param>
/// <param name="assembliesResolver">The assembly resolver.</param>
/// <returns>Null or the CLR type.</returns>
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);
}
}
}
84 changes: 84 additions & 0 deletions src/Microsoft.AspNetCore.OData/Edm/TypeCacheItem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
//-----------------------------------------------------------------------------
// <copyright file="TypeCacheItem.cs" company=".NET Foundation">
// Copyright (c) .NET Foundation and Contributors. All rights reserved.
// See License.txt in the project root for license information.
// </copyright>
//------------------------------------------------------------------------------

using System;
using System.Collections.Concurrent;
using Microsoft.OData.Edm;

namespace Microsoft.AspNetCore.OData.Edm
{
internal class TypeCacheItem
{
#region ClrType => EdmType
/// <summary>
/// <see cref="Type"/> to <see cref="IEdmTypeReference"/>.
/// </summary>
public ConcurrentDictionary<Type, IEdmTypeReference> ClrToEdmTypeCache { get; } = new ConcurrentDictionary<Type, IEdmTypeReference>();

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
/// <summary>
/// <see cref="IEdmType"/> to <see cref="Type"/>.
/// item1: non-nullable
/// item2: nullable
/// </summary>
public ConcurrentDictionary<IEdmType, (Type, Type)> EdmToClrTypeCache { get; } = new ConcurrentDictionary<IEdmType, (Type, Type)>();

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
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand All @@ -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);
}

Expand Down Expand Up @@ -113,7 +113,6 @@ public static string GetUriRepresentationForValue(object value, TimeZoneInfo tim
}
else
{
Contract.Assert(type.GetEdmPrimitiveType() != null);
value = ODataPrimitiveSerializer.ConvertUnsupportedPrimitives(value, timeZone);
}

Expand Down
Loading