/// <summary> /// Creates a new instance of <see cref="RelationalTypeMappingInfo" />. /// </summary> /// <param name="member"> The property or field for which mapping is needed. </param> public RelationalTypeMappingInfo([NotNull] MemberInfo member) { Check.NotNull(member, nameof(member)); _coreTypeMappingInfo = new TypeMappingInfo(member); if (Attribute.IsDefined(member, typeof(ColumnAttribute), inherit: true)) { var attribute = member.GetCustomAttributes <ColumnAttribute>(inherit: true).First(); StoreTypeName = attribute.TypeName; StoreTypeNameBase = ParseStoreTypeName( attribute.TypeName, out _parsedSize, out _parsedPrecision, out _parsedScale, out _isMax); } else { StoreTypeName = null; StoreTypeNameBase = null; _parsedSize = null; _parsedPrecision = null; _parsedScale = null; _isMax = false; } IsFixedLength = null; }
/// <summary> /// Creates a new instance of <see cref="RelationalTypeMappingInfo" />. /// </summary> /// <param name="member"> The property or field for which mapping is needed. </param> public RelationalTypeMappingInfo([NotNull] MemberInfo member) { Check.NotNull(member, nameof(member)); _coreTypeMappingInfo = new TypeMappingInfo(member); var attribute = member.GetCustomAttributes <ColumnAttribute>(true)?.FirstOrDefault(); if (attribute != null) { StoreTypeName = attribute.TypeName; StoreTypeNameBase = ParseStoreTypeName(attribute.TypeName, out _parsedSize, out _parsedPrecision, out _parsedScale, out _isMax); } else { StoreTypeName = null; StoreTypeNameBase = null; _parsedSize = null; _parsedPrecision = null; _parsedScale = null; _isMax = false; } IsFixedLength = false; }
/// <summary> /// Creates a new instance of <see cref="RelationalTypeMappingInfo" />. /// </summary> /// <param name="principals"> The principal property chain for the property for which mapping is needed. </param> public RelationalTypeMappingInfo([NotNull] IReadOnlyList <IProperty> principals) { _coreTypeMappingInfo = new TypeMappingInfo(principals); string storeTypeName = null; bool? fixedLength = null; for (var i = 0; i < principals.Count; i++) { var principal = principals[i]; if (storeTypeName == null) { var columnType = (string)principal[RelationalAnnotationNames.ColumnType]; if (columnType != null) { storeTypeName = columnType; } } if (fixedLength == null) { fixedLength = principal.Relational().IsFixedLength; } } IsFixedLength = fixedLength; StoreTypeName = storeTypeName; StoreTypeNameBase = ParseStoreTypeName(storeTypeName, out _parsedSize, out _parsedPrecision, out _parsedScale, out _isMax); }
/// <summary> /// Creates a new instance of <see cref="RelationalTypeMappingInfo" />. /// </summary> /// <param name="storeTypeName"> The provider-specific relational type name for which mapping is needed. </param> public RelationalTypeMappingInfo([NotNull] string storeTypeName) { Check.NotEmpty(storeTypeName, nameof(storeTypeName)); _coreTypeMappingInfo = new TypeMappingInfo(); IsFixedLength = false; StoreTypeName = storeTypeName; StoreTypeNameBase = ParseStoreTypeName(storeTypeName, out _parsedSize, out _parsedPrecision, out _parsedScale, out _isMax); }
/// <summary> /// Compares this <see cref="TypeMappingInfo" /> to another to check if they represent the same mapping. /// </summary> /// <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) => ClrType == other.ClrType && MemberInfo == other.MemberInfo && IsKeyOrIndex == other.IsKeyOrIndex && Size == other.Size && IsUnicode == other.IsUnicode && IsRowVersion == other.IsRowVersion && Precision == other.Precision && Scale == other.Scale;
/// <summary> /// Creates a new instance of <see cref="RelationalTypeMappingInfo" />. /// </summary> /// <param name="storeTypeName"> The provider-specific relational type name for which mapping is needed. </param> public RelationalTypeMappingInfo([NotNull] string storeTypeName) { // Note: Empty string is allowed for store type name because SQLite Check.NotNull(storeTypeName, nameof(storeTypeName)); _coreTypeMappingInfo = new TypeMappingInfo(); StoreTypeName = storeTypeName; StoreTypeNameBase = ParseStoreTypeName(storeTypeName, out _parsedSize, out _parsedPrecision, out _parsedScale, out _isMax); IsFixedLength = null; }
/// <summary> /// Compares this <see cref="TypeMappingInfo" /> to another to check if they represent the same mapping. /// </summary> /// <param name="other"> The other object. </param> /// <returns> <c>True</c> if they represent the same mapping; <c>false</c> otherwise. </returns> public bool Equals(TypeMappingInfo other) => ClrType == other.ClrType && _providerClrType == other._providerClrType && _customConverter == other._customConverter && IsKeyOrIndex == other.IsKeyOrIndex && Size == other.Size && IsUnicode == other.IsUnicode && IsRowVersion == other.IsRowVersion && Precision == other.Precision && Scale == other.Scale;
/// <summary> /// Compares this <see cref="TypeMappingInfo" /> to another to check if they represent the same mapping. /// </summary> /// <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) => ModelClrType == other.ModelClrType && MemberInfo == other.MemberInfo && ConfiguredProviderClrType == other.ConfiguredProviderClrType && IsKeyOrIndex == other.IsKeyOrIndex && Size == other.Size && IsUnicode == other.IsUnicode && IsRowVersion == other.IsRowVersion && Precision == other.Precision && Scale == other.Scale && Equals(_customConverter, other._customConverter);
/// <summary> /// Creates a new instance of <see cref="RelationalTypeMappingInfo" />. /// </summary> /// <param name="type"> The CLR type in the model for which mapping is needed. </param> public RelationalTypeMappingInfo([NotNull] Type type) { _coreTypeMappingInfo = new TypeMappingInfo(type); StoreTypeName = null; StoreTypeNameBase = null; IsFixedLength = null; _parsedSize = null; _parsedPrecision = null; _parsedScale = null; _isMax = false; }
/// <summary> /// Compares this <see cref="TypeMappingInfo" /> to another to check if they represent the same mapping. /// </summary> /// <param name="other"> The other object. </param> /// <returns> <c>True</c> if they represent the same mapping; <c>false</c> otherwise. </returns> protected bool Equals(TypeMappingInfo other) => ModelClrType == other.ModelClrType && StoreClrType == other.StoreClrType && IsKeyOrIndex == other.IsKeyOrIndex && Size == other.Size && IsUnicode == other.IsUnicode && IsRowVersion == other.IsRowVersion && IsFixedLength == other.IsFixedLength && Precision == other.Precision && Scale == other.Scale && Equals(_customConverter, other._customConverter);
/// <summary> /// Creates a new instance of <see cref="RelationalTypeMappingInfo" />. /// </summary> /// <param name="storeTypeName">The provider-specific relational type name for which mapping is needed.</param> /// <param name="storeTypeNameBase">The provider-specific relational type name, with any facets removed.</param> /// <param name="unicode">Specifies Unicode or ANSI mapping, or <see langword="null" /> for default.</param> /// <param name="size">Specifies a size for the mapping, or <see langword="null" /> for default.</param> /// <param name="precision">Specifies a precision for the mapping, or <see langword="null" /> for default.</param> /// <param name="scale">Specifies a scale for the mapping, or <see langword="null" /> for default.</param> public RelationalTypeMappingInfo( string storeTypeName, string storeTypeNameBase, bool?unicode, int?size, int?precision, int?scale) { // Note: Empty string is allowed for store type name because SQLite _coreTypeMappingInfo = new TypeMappingInfo(null, false, unicode, size, null, precision, scale); StoreTypeName = storeTypeName; StoreTypeNameBase = storeTypeNameBase; IsFixedLength = null; }
/// <summary> /// Creates a new instance of <see cref="RelationalTypeMappingInfo" />. /// </summary> /// <param name="member">The property or field for which mapping is needed.</param> /// <param name="storeTypeName">The provider-specific relational type name for which mapping is needed.</param> /// <param name="storeTypeNameBase">The provider-specific relational type name, with any facets removed.</param> /// <param name="unicode">Specifies Unicode or ANSI mapping, or <see langword="null" /> for default.</param> /// <param name="size">Specifies a size for the mapping, or <see langword="null" /> for default.</param> /// <param name="precision">Specifies a precision for the mapping, or <see langword="null" /> for default.</param> /// <param name="scale">Specifies a scale for the mapping, or <see langword="null" /> for default.</param> public RelationalTypeMappingInfo( MemberInfo member, string?storeTypeName = null, string?storeTypeNameBase = null, bool?unicode = null, int?size = null, int?precision = null, int?scale = null) { _coreTypeMappingInfo = new TypeMappingInfo(member, unicode, size, precision, scale); StoreTypeName = storeTypeName; StoreTypeNameBase = storeTypeNameBase; IsFixedLength = null; }
/// <summary> /// Creates a new instance of <see cref="RelationalTypeMappingInfo" />. /// </summary> /// <param name="principals">The principal property chain for the property for which mapping is needed.</param> /// <param name="storeTypeName">The provider-specific relational type name for which mapping is needed.</param> /// <param name="storeTypeNameBase">The provider-specific relational type name, with any facets removed.</param> /// <param name="fallbackUnicode"> /// Specifies a fallback Specifies Unicode or ANSI mapping for the mapping, in case one isn't found at the core /// level, or <see langword="null" /> for default. /// </param> /// <param name="fixedLength">Specifies a fixed length mapping, or <see langword="null" /> for default.</param> /// <param name="fallbackSize"> /// Specifies a fallback size for the mapping, in case one isn't found at the core level, or <see langword="null" /> for /// default. /// </param> /// <param name="fallbackPrecision"> /// Specifies a fallback precision for the mapping, in case one isn't found at the core level, or <see langword="null" /> /// for default. /// </param> /// <param name="fallbackScale"> /// Specifies a fallback scale for the mapping, in case one isn't found at the core level, or <see langword="null" /> for /// default. /// </param> public RelationalTypeMappingInfo( IReadOnlyList <IProperty> principals, string?storeTypeName = null, string?storeTypeNameBase = null, bool?fallbackUnicode = null, bool?fixedLength = null, int?fallbackSize = null, int?fallbackPrecision = null, int?fallbackScale = null) { _coreTypeMappingInfo = new TypeMappingInfo(principals, fallbackUnicode, fallbackSize, fallbackPrecision, fallbackScale); IsFixedLength = fixedLength; StoreTypeName = storeTypeName; StoreTypeNameBase = storeTypeNameBase; }
/// <summary> /// Creates a new instance of <see cref="RelationalTypeMappingInfo" />. /// </summary> /// <param name="member"> The property or field for which mapping is needed. </param> /// <param name="storeTypeName"> The provider-specific relational type name for which mapping is needed. </param> /// <param name="storeTypeNameBase"> The provider-specific relational type name, with any facets removed. </param> /// <param name="unicode"> Specifies Unicode or ANSI mapping, or <c>null</c> for default. </param> /// <param name="size"> Specifies a size for the mapping, or <c>null</c> for default. </param> /// <param name="precision"> Specifies a precision for the mapping, or <c>null</c> for default. </param> /// <param name="scale"> Specifies a scale for the mapping, or <c>null</c> for default. </param> public RelationalTypeMappingInfo( [NotNull] MemberInfo member, [CanBeNull] string storeTypeName = null, [CanBeNull] string storeTypeNameBase = null, bool?unicode = null, int?size = null, int?precision = null, int?scale = null) { Check.NotNull(member, nameof(member)); _coreTypeMappingInfo = new TypeMappingInfo(member, unicode, size, precision, scale); StoreTypeName = storeTypeName; StoreTypeNameBase = storeTypeNameBase; IsFixedLength = null; }
/// <summary> /// Creates a new instance of <see cref="TypeMappingInfo" />. /// </summary> /// <param name="type"> The CLR type in the model for which mapping is needed. </param> /// <param name="storeTypeName"> The database type name. </param> /// <param name="keyOrIndex"> If <c>true</c>, then a special mapping for a key or index may be returned. </param> /// <param name="unicode"> Specifies Unicode or ANSI mapping, or <c>null</c> for default. </param> /// <param name="size"> Specifies a size for the mapping, or <c>null</c> for default. </param> /// <param name="rowVersion"> Specifies a row-version, or <c>null</c> for default. </param> /// <param name="fixedLength"> Specifies a fixed length mapping, or <c>null</c> for default. </param> /// <param name="precision"> Specifies a precision for the mapping, or <c>null</c> for default. </param> /// <param name="scale"> Specifies a scale for the mapping, or <c>null</c> for default. </param> public RelationalTypeMappingInfo( [NotNull] Type type, [CanBeNull] string storeTypeName, bool keyOrIndex, bool?unicode, int?size, bool?rowVersion, bool?fixedLength, int?precision, int?scale) { _coreTypeMappingInfo = new TypeMappingInfo(type, keyOrIndex, unicode, size, rowVersion, precision, scale); IsFixedLength = fixedLength; StoreTypeName = storeTypeName; StoreTypeNameBase = ParseStoreTypeName(storeTypeName, out _parsedSize, out _parsedPrecision, out _parsedScale, out _isMax); }
/// <summary> /// Creates a new instance of <see cref="RelationalTypeMappingInfo" /> with the given <see cref="ValueConverterInfo" />. /// </summary> /// <param name="source"> The source info. </param> /// <param name="converter"> The converter to apply. </param> public RelationalTypeMappingInfo( RelationalTypeMappingInfo source, ValueConverterInfo converter) { _coreTypeMappingInfo = new TypeMappingInfo( source._coreTypeMappingInfo, converter, source.IsUnicode, source.Size, source.Precision, source.Scale); var mappingHints = converter.MappingHints; StoreTypeName = source.StoreTypeName; StoreTypeNameBase = ParseStoreTypeName(source.StoreTypeName, out _parsedSize, out _parsedPrecision, out _parsedScale, out _isMax); IsFixedLength = source.IsFixedLength ?? (mappingHints as RelationalConverterMappingHints)?.IsFixedLength; }
/// <summary> /// Creates a new instance of <see cref="RelationalTypeMappingInfo" />. /// </summary> /// <param name="property"> The property for which mapping is needed. </param> public RelationalTypeMappingInfo([NotNull] IProperty property) { _coreTypeMappingInfo = new TypeMappingInfo(property); var principals = property.FindPrincipals().ToList(); var storeTypeName = principals .Select(p => (string)p[RelationalAnnotationNames.ColumnType]) .FirstOrDefault(t => t != null); var fixedLength = principals .Select(p => p.Relational().IsFixedLength) .FirstOrDefault(t => t); IsFixedLength = fixedLength; StoreTypeName = storeTypeName; StoreTypeNameBase = ParseStoreTypeName(storeTypeName, out _parsedSize, out _parsedPrecision, out _parsedScale, out _isMax); }
/// <summary> /// Creates a new instance of <see cref="TypeMappingInfo" /> with the given <see cref="ValueConverterInfo" />. /// </summary> /// <param name="source"> The source info. </param> /// <param name="converter"> The converter to apply. </param> protected TypeMappingInfo( [NotNull] TypeMappingInfo source, ValueConverterInfo converter) { Check.NotNull(source, nameof(source)); Property = source.Property; IsRowVersion = source.IsRowVersion; IsKeyOrIndex = source.IsKeyOrIndex; MemberInfo = source.MemberInfo; var mappingHints = converter.MappingHints; Size = source.Size ?? mappingHints?.Size; IsUnicode = source.IsUnicode ?? mappingHints?.IsUnicode; Scale = source.Scale ?? mappingHints?.Scale; Precision = source.Precision ?? mappingHints?.Precision; ClrType = converter.ProviderClrType.UnwrapNullableType(); }
/// <summary> /// Creates a new instance of <see cref="TypeMappingInfo" /> with the given <see cref="ValueConverterInfo" />. /// </summary> /// <param name="source"> The source info. </param> /// <param name="builtInConverter"> The converter to apply. </param> protected TypeMappingInfo( [NotNull] TypeMappingInfo source, ValueConverterInfo builtInConverter) { Check.NotNull(source, nameof(source)); Property = source.Property; ModelClrType = source.ModelClrType; ConfiguredProviderClrType = source.ConfiguredProviderClrType; IsRowVersion = source.IsRowVersion; IsKeyOrIndex = source.IsKeyOrIndex; if (source._customConverter != null) { _customConverter = source._customConverter; ValueConverterInfo = new ValueConverterInfo( _customConverter.ModelClrType, builtInConverter.ProviderClrType, i => _customConverter.ComposeWith(builtInConverter.Create()), builtInConverter.MappingHints == null ? _customConverter.MappingHints : builtInConverter.MappingHints.With(_customConverter.MappingHints)); } else { ValueConverterInfo = builtInConverter; } // ReSharper disable once VirtualMemberCallInConstructor var mappingHints = ValueConverterInfo?.MappingHints; Size = source.Size ?? mappingHints?.Size; IsUnicode = source.IsUnicode ?? mappingHints?.IsUnicode; Scale = source.Scale ?? mappingHints?.Scale; Precision = source.Precision ?? mappingHints?.Precision; ProviderClrType = CreateProviderClrType(); }
/// <summary> /// Creates a new instance of <see cref="TypeMappingInfo" /> with the given <see cref="ValueConverterInfo" />. /// </summary> /// <param name="source"> The source info. </param> /// <param name="builtInConverter"> The converter to apply. </param> protected TypeMappingInfo( [NotNull] TypeMappingInfo source, ValueConverterInfo builtInConverter) { Check.NotNull(source, nameof(source)); Property = source.Property; ModelClrType = source.ModelClrType; StoreClrType = source.StoreClrType; IsRowVersion = source.IsRowVersion; IsKeyOrIndex = source.IsKeyOrIndex; if (source._customConverter != null) { _customConverter = source._customConverter; ValueConverterInfo = new ValueConverterInfo( _customConverter.ModelType, builtInConverter.StoreClrType, i => _customConverter.ComposeWith(builtInConverter.Create()), _customConverter.MappingHints.With(builtInConverter.MappingHints)); } else { ValueConverterInfo = builtInConverter; } // ReSharper disable once VirtualMemberCallInConstructor var mappingHints = ValueConverterInfo?.MappingHints ?? default; Size = CalculateSize(mappingHints, source.Size ?? mappingHints.Size); IsUnicode = source.IsUnicode ?? mappingHints.IsUnicode; IsFixedLength = source.IsFixedLength ?? mappingHints.IsFixedLength; Scale = source.Scale ?? mappingHints.Scale; Precision = source.Precision ?? mappingHints.Precision; }
/// <summary> /// Creates a new instance of <see cref="TypeMappingInfo" /> with the given <see cref="ValueConverterInfo" />. /// </summary> /// <param name="source"> The source info. </param> /// <param name="converter"> The converter to apply. </param> /// <param name="unicode"> Specifies Unicode or ANSI mapping, or <c>null</c> for default. </param> /// <param name="size"> Specifies a size for the mapping, or <c>null</c> for default. </param> /// <param name="precision"> Specifies a precision for the mapping, or <c>null</c> for default. </param> /// <param name="scale"> Specifies a scale for the mapping, or <c>null</c> for default. </param> public TypeMappingInfo( TypeMappingInfo source, ValueConverterInfo converter, bool?unicode = null, int?size = null, int?precision = null, int?scale = null) { Check.NotNull(source, nameof(source)); IsRowVersion = source.IsRowVersion; IsKeyOrIndex = source.IsKeyOrIndex; _providerClrType = source._providerClrType; _customConverter = source._customConverter; var mappingHints = converter.MappingHints; Size = size ?? source.Size ?? mappingHints?.Size; IsUnicode = unicode ?? source.IsUnicode ?? mappingHints?.IsUnicode; Scale = scale ?? source.Scale ?? mappingHints?.Scale; Precision = precision ?? source.Precision ?? mappingHints?.Precision; ClrType = converter.ProviderClrType.UnwrapNullableType(); }
/// <summary> /// <para> /// Overridden by database providers to find a type mapping for the given info. /// </para> /// <para> /// The mapping info is populated with as much information about the required type mapping as /// is available. Use all the information necessary to create the best mapping. Return <c>null</c> /// if no mapping is available. /// </para> /// </summary> /// <param name="mappingInfo"> The mapping info to use to create the mapping. </param> /// <returns> The type mapping, or <c>null</c> if none could be found. </returns> protected abstract CoreTypeMapping FindMapping(TypeMappingInfo mappingInfo);
private CoreTypeMapping FindMappingWithConversion( TypeMappingInfo mappingInfo, [CanBeNull] IProperty property) { Check.NotNull(mappingInfo, nameof(mappingInfo)); var principals = property?.FindPrincipals().ToList(); var customConverter = principals ?.Select(p => p.GetValueConverter()) .FirstOrDefault(c => c != null); 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) : null; if (mapping == null) { var sourceType = mappingInfo.ClrType; if (sourceType != null) { foreach (var converterInfo in Dependencies .ValueConverterSelector .Select(sourceType, providerClrType)) { var mappingInfoUsed = mappingInfo.WithConverter(converterInfo); mapping = FindMapping(mappingInfoUsed); if (mapping == null && providerClrType != null) { foreach (var secondConverterInfo in Dependencies .ValueConverterSelector .Select(providerClrType)) { mapping = FindMapping(mappingInfoUsed.WithConverter(secondConverterInfo)); if (mapping != null) { mapping = mapping.Clone(secondConverterInfo.Create()); break; } } } if (mapping != null) { mapping = mapping.Clone(converterInfo.Create()); break; } } } } if (mapping != null && customConverter != null) { mapping = mapping.Clone(customConverter); } return(mapping); }); ValidateMapping(resolvedMapping, property); return(resolvedMapping); }
/// <summary> /// <para> /// Uses any available <see cref="ValueConverter" /> to help find a mapping that works. /// </para> /// <para> /// Note: providers should typically not need to override this method. /// </para> /// </summary> /// <param name="mappingInfo"> The mapping info. </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) { 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); if (customConverter != null) { mappingInfo = mappingInfo.WithConverter( new ValueConverterInfo( customConverter.ModelClrType, customConverter.ProviderClrType, i => customConverter, customConverter.MappingHints)); } var providerClrType = principals ?.Select(p => p.GetProviderClrType()) .FirstOrDefault(t => t != null) ?.UnwrapNullableType(); var mapping = providerClrType == null || providerClrType == mappingInfo.ClrType ? FindMapping(mappingInfo) : null; if (mapping == null) { var sourceType = mappingInfo.ClrType; if (sourceType != null) { foreach (var converterInfo in Dependencies .ValueConverterSelector .Select(sourceType, providerClrType)) { var mappingInfoUsed = mappingInfo.WithConverter(converterInfo); mapping = FindMapping(mappingInfoUsed); if (mapping == null && providerClrType != null) { foreach (var secondConverterInfo in Dependencies .ValueConverterSelector .Select(providerClrType)) { mapping = FindMapping(mappingInfoUsed.WithConverter(secondConverterInfo)); if (mapping != null) { mapping = mapping.Clone(secondConverterInfo.Create()); break; } } } if (mapping != null) { mapping = mapping.Clone(converterInfo.Create()); break; } } } } if (mapping != null && customConverter != null) { mapping = mapping.Clone(customConverter); } return mapping; })); }
/// <summary> /// Overridden to call <see cref="FindMapping(RelationalTypeMappingInfo)" /> /// </summary> /// <param name="mappingInfo"> The mapping info to use to create the mapping. </param> /// <returns> The type mapping, or <c>null</c> if none could be found. </returns> protected override CoreTypeMapping FindMapping(TypeMappingInfo mappingInfo) => throw new InvalidOperationException("FindMapping on a 'RelationalTypeMappingSource' with a non-relational 'TypeMappingInfo'.");
/// <summary> /// <para> /// Uses any available <see cref="ValueConverter" /> to help find a mapping that works. /// </para> /// <para> /// Note: providers should typically not need to override this method. /// </para> /// </summary> /// <param name="mappingInfo"> The mapping info. </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) { Check.NotNull(mappingInfo, nameof(mappingInfo)); return(_explicitMappings.GetOrAdd( mappingInfo, k => { var mappingInfoUsed = mappingInfo; var mapping = mappingInfoUsed.ConfiguredProviderClrType == null || mappingInfoUsed.ConfiguredProviderClrType == mappingInfoUsed.ModelClrType ? FindMapping(mappingInfoUsed) : null; if (mapping == null) { var sourceType = mappingInfo.ValueConverterInfo?.ProviderClrType ?? mappingInfo.ModelClrType; if (sourceType != null) { foreach (var converterInfo in Dependencies .ValueConverterSelector .Select(sourceType, mappingInfo.ConfiguredProviderClrType)) { mappingInfoUsed = mappingInfo.WithBuiltInConverter(converterInfo); mapping = FindMapping(mappingInfoUsed); if (mapping == null && mappingInfo.ConfiguredProviderClrType != null) { foreach (var secondConverterInfo in Dependencies .ValueConverterSelector .Select(mappingInfo.ConfiguredProviderClrType)) { var secondMappingInfoUsed = mappingInfoUsed.WithBuiltInConverter(secondConverterInfo); mapping = FindMapping(secondMappingInfoUsed); if (mapping != null) { mapping = mapping.Clone(secondMappingInfoUsed.ValueConverterInfo?.Create()); break; } } } if (mapping != null) { break; } } } } if (mapping != null && mappingInfoUsed.ValueConverterInfo != null) { mapping = mapping.Clone(mappingInfoUsed.ValueConverterInfo?.Create()); } return mapping; })); }
/// <summary> /// <para> /// Overridden by database providers to find a type mapping for the given info. /// </para> /// <para> /// The mapping info is populated with as much information about the required type mapping as /// is available. Use all the information necessary to create the best mapping. Return <c>null</c> /// if no mapping is available. /// </para> /// </summary> /// <param name="mappingInfo"> The mapping info to use to create the mapping. </param> /// <returns> The type mapping, or <c>null</c> if none could be found. </returns> protected abstract CoreTypeMapping FindMapping([NotNull] TypeMappingInfo mappingInfo);
/// <summary> /// Overridden to call <see cref="FindMapping(RelationalTypeMappingInfo)" /> /// </summary> /// <param name="mappingInfo"> The mapping info to use to create the mapping. </param> /// <returns> The type mapping, or <c>null</c> if none could be found. </returns> protected override CoreTypeMapping FindMapping(TypeMappingInfo mappingInfo) => FindMapping((RelationalTypeMappingInfo)mappingInfo);