Skip to content

Commit

Permalink
Merge branch 'release/2.1' into dev
Browse files Browse the repository at this point in the history
  • Loading branch information
ajcvickers committed Mar 26, 2018
2 parents 8a40286 + c7d8f26 commit fb6283a
Show file tree
Hide file tree
Showing 5 changed files with 99 additions and 68 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

using System;
using JetBrains.Annotations;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Utilities;

namespace Microsoft.EntityFrameworkCore.Storage.Internal
Expand All @@ -17,6 +18,9 @@ public class FallbackRelationalTypeMappingSource : RelationalTypeMappingSource
private readonly IRelationalTypeMapper _relationalTypeMapper;
#pragma warning restore 618

[ThreadStatic]
private static IProperty _property;

/// <summary>
/// This API supports the Entity Framework Core infrastructure and is not intended to be used
/// directly from your code. This API may change or be removed in future releases.
Expand All @@ -32,6 +36,19 @@ public FallbackRelationalTypeMappingSource(
_relationalTypeMapper = typeMapper;
}

/// <summary>
/// This API supports the Entity Framework Core infrastructure and is not intended to be used
/// directly from your code. This API may change or be removed in future releases.
/// </summary>
protected override CoreTypeMapping FindMappingWithConversion(
TypeMappingInfo mappingInfo,
IProperty property)
{
_property = property;

return base.FindMappingWithConversion(mappingInfo, property);
}

/// <summary>
/// This API supports the Entity Framework Core infrastructure and is not intended to be used
/// directly from your code. This API may change or be removed in future releases.
Expand Down Expand Up @@ -67,8 +84,8 @@ protected override RelationalTypeMapping FindMapping(RelationalTypeMappingInfo m
}

private RelationalTypeMapping FindMappingForProperty(RelationalTypeMappingInfo mappingInfo)
=> mappingInfo.Property != null
? _relationalTypeMapper.FindMapping(mappingInfo.Property)
=> _property != null
? _relationalTypeMapper.FindMapping(_property)
: null;

private RelationalTypeMapping FindMappingForClrType(RelationalTypeMappingInfo mappingInfo)
Expand Down
10 changes: 5 additions & 5 deletions src/EFCore.Relational/Storage/RelationalTypeMappingSource.cs
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ protected override CoreTypeMapping FindMapping(TypeMappingInfo mappingInfo)
/// <returns> The type mapping, or <c>null</c> if none was found. </returns>
public override CoreTypeMapping FindMapping(IProperty property)
=> property.FindRelationalMapping()
?? FindMappingWithConversion(new ConcreteRelationalTypeMappingInfo(property));
?? FindMappingWithConversion(new ConcreteRelationalTypeMappingInfo(property), property);

/// <summary>
/// <para>
Expand All @@ -95,7 +95,7 @@ public override CoreTypeMapping FindMapping(IProperty property)
/// <param name="type"> The CLR type. </param>
/// <returns> The type mapping, or <c>null</c> if none was found. </returns>
public override CoreTypeMapping FindMapping(Type type)
=> FindMappingWithConversion(new ConcreteRelationalTypeMappingInfo(type));
=> FindMappingWithConversion(new ConcreteRelationalTypeMappingInfo(type), null);

/// <summary>
/// <para>
Expand All @@ -113,7 +113,7 @@ public override CoreTypeMapping FindMapping(Type type)
/// <param name="member"> The field or property. </param>
/// <returns> The type mapping, or <c>null</c> if none was found. </returns>
public override CoreTypeMapping FindMapping(MemberInfo member)
=> FindMappingWithConversion(new ConcreteRelationalTypeMappingInfo(member));
=> FindMappingWithConversion(new ConcreteRelationalTypeMappingInfo(member), null);

/// <summary>
/// <para>
Expand All @@ -130,7 +130,7 @@ public override CoreTypeMapping FindMapping(MemberInfo member)
/// <param name="storeTypeName"> The database type name. </param>
/// <returns> The type mapping, or <c>null</c> if none was found. </returns>
public virtual RelationalTypeMapping FindMapping(string storeTypeName)
=> (RelationalTypeMapping)FindMappingWithConversion(new ConcreteRelationalTypeMappingInfo(storeTypeName));
=> (RelationalTypeMapping)FindMappingWithConversion(new ConcreteRelationalTypeMappingInfo(storeTypeName), null);

/// <summary>
/// <para>
Expand Down Expand Up @@ -164,7 +164,7 @@ public virtual RelationalTypeMapping FindMapping(
int? scale = null)
=> (RelationalTypeMapping)FindMappingWithConversion(
new ConcreteRelationalTypeMappingInfo(
type, keyOrIndex, unicode, size, rowVersion, fixedLength, precision, scale));
type, keyOrIndex, unicode, size, rowVersion, fixedLength, precision, scale), null);

RelationalTypeMapping IRelationalTypeMappingSource.FindMapping(IProperty property)
=> (RelationalTypeMapping)FindMapping(property);
Expand Down
25 changes: 14 additions & 11 deletions src/EFCore.SqlServer/Storage/Internal/SqlServerTypeMappingSource.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
using System.Linq;
using JetBrains.Annotations;
using Microsoft.EntityFrameworkCore.ChangeTracking;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.SqlServer.Internal;
using Microsoft.EntityFrameworkCore.Storage;

Expand Down Expand Up @@ -204,26 +205,28 @@ public SqlServerTypeMappingSource(
/// This API supports the Entity Framework Core infrastructure and is not intended to be used
/// directly from your code. This API may change or be removed in future releases.
/// </summary>
protected override RelationalTypeMapping FindMapping(RelationalTypeMappingInfo mappingInfo)
protected override void ValidateMapping(CoreTypeMapping mapping, IProperty property)
{
var mapping = FindRawMapping(mappingInfo)?.Clone(mappingInfo);
var relationalMapping = mapping as RelationalTypeMapping;

if (_disallowedMappings.Contains(mapping?.StoreType))
if (_disallowedMappings.Contains(relationalMapping?.StoreType))
{
var propertyName = mappingInfo.Property?.Name
?? mappingInfo.MemberInfo?.Name;

if (propertyName == null)
if (property== null)
{
throw new ArgumentException(SqlServerStrings.UnqualifiedDataType(mapping.StoreType));
throw new ArgumentException(SqlServerStrings.UnqualifiedDataType(relationalMapping.StoreType));
}

throw new ArgumentException(SqlServerStrings.UnqualifiedDataTypeOnProperty(mapping.StoreType, propertyName));
throw new ArgumentException(SqlServerStrings.UnqualifiedDataTypeOnProperty(relationalMapping.StoreType, property.Name));
}

return mapping;
}

/// <summary>
/// This API supports the Entity Framework Core infrastructure and is not intended to be used
/// directly from your code. This API may change or be removed in future releases.
/// </summary>
protected override RelationalTypeMapping FindMapping(RelationalTypeMappingInfo mappingInfo)
=> FindRawMapping(mappingInfo)?.Clone(mappingInfo);

private RelationalTypeMapping FindRawMapping(RelationalTypeMappingInfo mappingInfo)
{
var clrType = mappingInfo.ClrType;
Expand Down
51 changes: 27 additions & 24 deletions src/EFCore/Storage/TypeMappingInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ namespace Microsoft.EntityFrameworkCore.Storage
/// </summary>
public abstract class TypeMappingInfo
{
private readonly Type _providerClrType;
private readonly ValueConverter _customConverter;

/// <summary>
/// Creates a new instance of <see cref="TypeMappingInfo" />.
/// </summary>
Expand All @@ -34,13 +37,24 @@ protected TypeMappingInfo([NotNull] IProperty property)

var principals = property.FindPrincipals().ToList();

Property = property;
MemberInfo = property.GetIdentifyingMemberInfo();
_providerClrType = principals
?.Select(p => p.GetProviderClrType())
.FirstOrDefault(t => t != null)
?.UnwrapNullableType();

_customConverter = principals
?.Select(p => p.GetValueConverter())
.FirstOrDefault(c => c != null);

var mappingHints = _customConverter?.MappingHints;

IsKeyOrIndex = property.IsKeyOrForeignKey() || property.IsIndex();
Size = principals.Select(p => p.GetMaxLength()).FirstOrDefault(t => t != null);
IsUnicode = principals.Select(p => p.IsUnicode()).FirstOrDefault(t => t != null);
Size = principals.Select(p => p.GetMaxLength()).FirstOrDefault(t => t != null) ?? mappingHints?.Size;
IsUnicode = principals.Select(p => p.IsUnicode()).FirstOrDefault(t => t != null) ?? mappingHints?.IsUnicode;
IsRowVersion = property.IsConcurrencyToken && property.ValueGenerated == ValueGenerated.OnAddOrUpdate;
ClrType = property.ClrType.UnwrapNullableType();
ClrType = (_customConverter?.ProviderClrType ?? property.ClrType).UnwrapNullableType();
Scale = mappingHints?.Scale;
Precision = mappingHints?.Precision;
}

/// <summary>
Expand All @@ -63,7 +77,6 @@ protected TypeMappingInfo([NotNull] MemberInfo member)
Check.NotNull(member, nameof(member));

ClrType = member.GetMemberType().UnwrapNullableType();
MemberInfo = member;
}

/// <summary>
Expand Down Expand Up @@ -105,10 +118,10 @@ protected TypeMappingInfo(
{
Check.NotNull(source, nameof(source));

Property = source.Property;
IsRowVersion = source.IsRowVersion;
IsKeyOrIndex = source.IsKeyOrIndex;
MemberInfo = source.MemberInfo;
_providerClrType = source._providerClrType;
_customConverter = source._customConverter;

var mappingHints = converter.MappingHints;

Expand All @@ -127,11 +140,6 @@ protected TypeMappingInfo(
/// <returns> The new mapping info. </returns>
public abstract TypeMappingInfo WithConverter(ValueConverterInfo converterInfo);

/// <summary>
/// The property for which mapping is needed.
/// </summary>
public virtual IProperty Property { get; }

/// <summary>
/// Indicates whether or not the mapping is part of a key or index.
/// </summary>
Expand Down Expand Up @@ -162,11 +170,6 @@ protected TypeMappingInfo(
/// </summary>
public virtual int? Scale { get; }

/// <summary>
/// The field or property info for the property.
/// </summary>
public virtual MemberInfo MemberInfo { get; }

/// <summary>
/// The CLR type in the model.
/// </summary>
Expand All @@ -178,9 +181,9 @@ protected TypeMappingInfo(
/// <param name="other"> The other object. </param>
/// <returns> <c>True</c> if they represent the same mapping; <c>false</c> otherwise. </returns>
protected virtual bool Equals([NotNull] TypeMappingInfo other)
=> Property == other.Property
&& ClrType == other.ClrType
&& MemberInfo == other.MemberInfo
=> ClrType == other.ClrType
&& _providerClrType == other._providerClrType
&& _customConverter == other._customConverter
&& IsKeyOrIndex == other.IsKeyOrIndex
&& Size == other.Size
&& IsUnicode == other.IsUnicode
Expand All @@ -205,11 +208,11 @@ public override bool Equals(object obj)
/// <returns> The hash code. </returns>
public override int GetHashCode()
{
var hashCode = Property?.GetHashCode() ?? 0;
hashCode = (hashCode * 397) ^ ClrType?.GetHashCode() ?? 0;
var hashCode = ClrType?.GetHashCode() ?? 0;
hashCode = (hashCode * 397) ^ (_providerClrType?.GetHashCode() ?? 0);
hashCode = (hashCode * 397) ^ (_customConverter?.GetHashCode() ?? 0);
hashCode = (hashCode * 397) ^ IsKeyOrIndex.GetHashCode();
hashCode = (hashCode * 397) ^ (Size?.GetHashCode() ?? 0);
hashCode = (hashCode * 397) ^ (MemberInfo?.GetHashCode() ?? 0);
hashCode = (hashCode * 397) ^ (IsUnicode?.GetHashCode() ?? 0);
hashCode = (hashCode * 397) ^ (IsRowVersion?.GetHashCode() ?? 0);
hashCode = (hashCode * 397) ^ (Scale?.GetHashCode() ?? 0);
Expand Down
60 changes: 34 additions & 26 deletions src/EFCore/Storage/TypeMappingSource.cs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,17 @@ protected TypeMappingSource([NotNull] TypeMappingSourceDependencies dependencies
/// <returns> The type mapping, or <c>null</c> if none could be found. </returns>
protected abstract CoreTypeMapping FindMapping([NotNull] TypeMappingInfo mappingInfo);

/// <summary>
/// Called after a mapping has been found so that it can be validated for the given property.
/// </summary>
/// <param name="mapping"> The mapping, if any. </param>
/// <param name="property"> The property, if any. </param>
protected virtual void ValidateMapping(
[CanBeNull] CoreTypeMapping mapping,
[CanBeNull] IProperty property)
{
}

/// <summary>
/// <para>
/// Uses any available <see cref="ValueConverter" /> to help find a mapping that works.
Expand All @@ -67,36 +78,29 @@ protected TypeMappingSource([NotNull] TypeMappingSourceDependencies dependencies
/// </para>
/// </summary>
/// <param name="mappingInfo"> The mapping info. </param>
/// <param name="property"> The property for which the type mapping is needed, if any. </param>
/// <returns> The type mapping with conversions applied, or <c>null</c> if none could be found. </returns>
protected virtual CoreTypeMapping FindMappingWithConversion([NotNull] TypeMappingInfo mappingInfo)
protected virtual CoreTypeMapping FindMappingWithConversion(
[NotNull] TypeMappingInfo mappingInfo,
[CanBeNull] IProperty property)
{
Check.NotNull(mappingInfo, nameof(mappingInfo));

return _explicitMappings.GetOrAdd(
mappingInfo,
k =>
{
var principals = mappingInfo.Property?.FindPrincipals().ToList();

var customConverter = principals
?.Select(p => p.GetValueConverter())
.FirstOrDefault(c => c != null);
var principals = property?.FindPrincipals().ToList();

if (customConverter != null)
{
mappingInfo = mappingInfo.WithConverter(
new ValueConverterInfo(
customConverter.ModelClrType,
customConverter.ProviderClrType,
i => customConverter,
customConverter.MappingHints));
}
var customConverter = principals
?.Select(p => p.GetValueConverter())
.FirstOrDefault(c => c != null);

var providerClrType = principals
?.Select(p => p.GetProviderClrType())
.FirstOrDefault(t => t != null)
?.UnwrapNullableType();
var providerClrType = principals
?.Select(p => p.GetProviderClrType())
.FirstOrDefault(t => t != null)
?.UnwrapNullableType();

var resolvedMapping = _explicitMappings.GetOrAdd(
mappingInfo,
k =>
{
var mapping = providerClrType == null
|| providerClrType == mappingInfo.ClrType
? FindMapping(mappingInfo)
Expand Down Expand Up @@ -149,6 +153,10 @@ protected virtual CoreTypeMapping FindMappingWithConversion([NotNull] TypeMappin

return mapping;
});

ValidateMapping(resolvedMapping, property);

return resolvedMapping;
}

/// <summary>
Expand All @@ -163,7 +171,7 @@ protected virtual CoreTypeMapping FindMappingWithConversion([NotNull] TypeMappin
/// <returns> The type mapping, or <c>null</c> if none was found. </returns>
public virtual CoreTypeMapping FindMapping(IProperty property)
=> property.FindMapping()
?? FindMappingWithConversion(new ConcreteTypeMappingInfo(property));
?? FindMappingWithConversion(new ConcreteTypeMappingInfo(property), property);

/// <summary>
/// <para>
Expand All @@ -181,7 +189,7 @@ public virtual CoreTypeMapping FindMapping(IProperty property)
/// <param name="type"> The CLR type. </param>
/// <returns> The type mapping, or <c>null</c> if none was found. </returns>
public virtual CoreTypeMapping FindMapping(Type type)
=> FindMappingWithConversion(new ConcreteTypeMappingInfo(type));
=> FindMappingWithConversion(new ConcreteTypeMappingInfo(type), null);

/// <summary>
/// <para>
Expand All @@ -199,7 +207,7 @@ public virtual CoreTypeMapping FindMapping(Type type)
/// <param name="member"> The field or property. </param>
/// <returns> The type mapping, or <c>null</c> if none was found. </returns>
public virtual CoreTypeMapping FindMapping(MemberInfo member)
=> FindMappingWithConversion(new ConcreteTypeMappingInfo(member));
=> FindMappingWithConversion(new ConcreteTypeMappingInfo(member), null);

private sealed class ConcreteTypeMappingInfo : TypeMappingInfo
{
Expand Down

0 comments on commit fb6283a

Please sign in to comment.