Skip to content

Commit

Permalink
Allow to ignore attributes when finding type mapping (#32193)
Browse files Browse the repository at this point in the history
Make existing model building conventions more extensible

Fixes #11124
Fixes #28866
  • Loading branch information
AndriySvyryd authored Nov 2, 2023
1 parent f168170 commit 60915e7
Show file tree
Hide file tree
Showing 31 changed files with 603 additions and 306 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,34 @@ protected override void ProcessEntityTypeAnnotations(
}
}

/// <summary>
/// Updates the complex type annotations that will be set on the read-only object.
/// </summary>
/// <param name="annotations">The annotations to be processed.</param>
/// <param name="complexType">The source complex type.</param>
/// <param name="runtimeComplexType">The target complex type that will contain the annotations.</param>
/// <param name="runtime">Indicates whether the given annotations are runtime annotations.</param>
protected override void ProcessComplexTypeAnnotations(
Dictionary<string, object?> annotations,
IComplexType complexType,
RuntimeComplexType runtimeComplexType,
bool runtime)
{
base.ProcessComplexTypeAnnotations(annotations, complexType, runtimeComplexType, runtime);

if (runtime)
{
annotations.Remove(RelationalAnnotationNames.TableMappings);
annotations.Remove(RelationalAnnotationNames.ViewMappings);
annotations.Remove(RelationalAnnotationNames.SqlQueryMappings);
annotations.Remove(RelationalAnnotationNames.FunctionMappings);
annotations.Remove(RelationalAnnotationNames.InsertStoredProcedureMappings);
annotations.Remove(RelationalAnnotationNames.DeleteStoredProcedureMappings);
annotations.Remove(RelationalAnnotationNames.UpdateStoredProcedureMappings);
annotations.Remove(RelationalAnnotationNames.DefaultMappings);
}
}

private static RuntimeEntityTypeMappingFragment Create(
IEntityTypeMappingFragment entityTypeMappingFragment,
RuntimeEntityType runtimeEntityType)
Expand Down
38 changes: 38 additions & 0 deletions src/EFCore.Relational/Storage/RelationalTypeMappingInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,44 @@ public RelationalTypeMappingInfo(
DbType = dbType;
}

/// <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="typeMappingConfiguration">The type mapping configuration.</param>
/// <param name="elementTypeMapping">The type mapping for elements, if known.</param>
/// <param name="storeTypeName">The database type name.</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(
Type type,
ITypeMappingConfiguration typeMappingConfiguration,
RelationalTypeMapping? elementTypeMapping = null,
string? storeTypeName = null,
string? storeTypeNameBase = null,
bool? unicode = null,
int? size = null,
int? precision = null,
int? scale = null)
{
_coreTypeMappingInfo = new TypeMappingInfo(
typeMappingConfiguration.GetValueConverter()?.ProviderClrType ?? type,
elementTypeMapping,
keyOrIndex: false,
unicode ?? typeMappingConfiguration.IsUnicode(),
size ?? typeMappingConfiguration.GetMaxLength(),
rowVersion: false,
precision ?? typeMappingConfiguration.GetPrecision(),
scale ?? typeMappingConfiguration.GetScale());

IsFixedLength = (bool?)typeMappingConfiguration[RelationalAnnotationNames.IsFixedLength];
StoreTypeName = storeTypeName;
StoreTypeNameBase = storeTypeNameBase;
}

/// <summary>
/// The core type mapping info.
/// </summary>
Expand Down
86 changes: 37 additions & 49 deletions src/EFCore.Relational/Storage/RelationalTypeMappingSource.cs
Original file line number Diff line number Diff line change
Expand Up @@ -343,66 +343,34 @@ protected override CoreTypeMapping FindMapping(in TypeMappingInfo mappingInfo)
{
type = type.UnwrapNullableType();
var typeConfiguration = model.FindTypeMappingConfiguration(type);
RelationalTypeMappingInfo mappingInfo;
Type? providerClrType = null;
ValueConverter? customConverter = null;
if (typeConfiguration == null)
if (typeConfiguration != null)
{
mappingInfo = new RelationalTypeMappingInfo(type, (RelationalTypeMapping?)elementMapping);
}
else
{
providerClrType = typeConfiguration.GetProviderClrType()?.UnwrapNullableType();
customConverter = typeConfiguration.GetValueConverter();

var isUnicode = typeConfiguration.IsUnicode();
var scale = typeConfiguration.GetScale();
var precision = typeConfiguration.GetPrecision();
var size = typeConfiguration.GetMaxLength();

bool? unicode = null;
int? scale = null;
int? precision = null;
int? size = null;
string? storeTypeNameBase = null;
var storeTypeName = (string?)typeConfiguration[RelationalAnnotationNames.ColumnType];
string? storeTypeBaseName = null;
if (storeTypeName != null)
{
storeTypeBaseName = ParseStoreTypeName(storeTypeName, ref isUnicode, ref size, ref precision, ref scale);
storeTypeNameBase = ParseStoreTypeName(storeTypeName, ref unicode, ref size, ref precision, ref scale);
}

var isFixedLength = (bool?)typeConfiguration[RelationalAnnotationNames.IsFixedLength];
mappingInfo = new RelationalTypeMappingInfo(
customConverter?.ProviderClrType ?? type,
(RelationalTypeMapping?)elementMapping,
storeTypeName,
storeTypeBaseName,
keyOrIndex: false,
unicode: isUnicode,
size: size,
rowVersion: false,
fixedLength: isFixedLength,
precision: precision,
scale: scale);
var mappingInfo = new RelationalTypeMappingInfo(type, typeConfiguration, (RelationalTypeMapping?)elementMapping,
storeTypeName, storeTypeNameBase, unicode, size, precision, scale);
var providerClrType = typeConfiguration.GetProviderClrType()?.UnwrapNullableType();
return FindMappingWithConversion(mappingInfo, providerClrType, customConverter: typeConfiguration.GetValueConverter());
}

return FindMappingWithConversion(mappingInfo, providerClrType, customConverter);
return FindMappingWithConversion(
new RelationalTypeMappingInfo(type, (RelationalTypeMapping?)elementMapping),
providerClrType: null,
customConverter: null);
}

/// <summary>
/// Finds the type mapping for a given <see cref="MemberInfo" /> representing
/// a field or a property of a CLR type.
/// </summary>
/// <remarks>
/// <para>
/// Note: Only call this method if there is no <see cref="IProperty" /> available, otherwise
/// call <see cref="FindMapping(IProperty)" />
/// </para>
/// <para>
/// Note: providers should typically not need to override this method.
/// </para>
/// </remarks>
/// <param name="member">The field or property.</param>
/// <returns>The type mapping, or <see langword="null" /> if none was found.</returns>
/// <inheritdoc/>
public override RelationalTypeMapping? FindMapping(MemberInfo member)
{
// TODO: Remove this, see #11124
if (member.GetCustomAttribute<ColumnAttribute>(true) is ColumnAttribute attribute)
{
var storeTypeName = attribute.TypeName;
Expand All @@ -417,7 +385,27 @@ protected override CoreTypeMapping FindMapping(in TypeMappingInfo mappingInfo)
new RelationalTypeMappingInfo(member, null, storeTypeName, storeTypeNameBase, unicode, size, precision, scale), null);
}

return FindMappingWithConversion(new RelationalTypeMappingInfo(member), null);
return FindMappingWithConversion(new RelationalTypeMappingInfo(member), null, null);
}

/// <inheritdoc/>
public override RelationalTypeMapping? FindMapping(MemberInfo member, IModel model, bool useAttributes)
{
if (useAttributes
&& member.GetCustomAttribute<ColumnAttribute>(true) is ColumnAttribute attribute)
{
var storeTypeName = attribute.TypeName;
bool? unicode = null;
int? size = null;
int? precision = null;
int? scale = null;
var storeTypeNameBase = ParseStoreTypeName(storeTypeName, ref unicode, ref size, ref precision, ref scale);

return FindMappingWithConversion(
new RelationalTypeMappingInfo(member, null, storeTypeName, storeTypeNameBase, unicode, size, precision, scale), null);
}

return FindMappingWithConversion(new RelationalTypeMappingInfo(member), null, null);
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,14 @@ public interface ICSharpRuntimeAnnotationCodeGenerator
/// <summary>
/// Generates code to create the given annotations.
/// </summary>
/// <param name="complexProperty">The entity type to which the annotations are applied.</param>
/// <param name="complexProperty">The complex property to which the annotations are applied.</param>
/// <param name="parameters">Additional parameters used during code generation.</param>
void Generate(IComplexProperty complexProperty, CSharpRuntimeAnnotationCodeGeneratorParameters parameters);

/// <summary>
/// Generates code to create the given annotations.
/// </summary>
/// <param name="complexType">The entity type to which the annotations are applied.</param>
/// <param name="complexType">The complex type to which the annotations are applied.</param>
/// <param name="parameters">Additional parameters used during code generation.</param>
void Generate(IComplexType complexType, CSharpRuntimeAnnotationCodeGeneratorParameters parameters);

Expand Down
2 changes: 1 addition & 1 deletion src/EFCore/Infrastructure/ModelValidator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,7 @@ void Validate(IConventionTypeBase typeBase)
}

var targetType = Dependencies.MemberClassifier.FindCandidateNavigationPropertyType(
clrProperty, conventionModel, out var targetOwned);
clrProperty, conventionModel, useAttributes: true, out var targetOwned);
if (targetType == null
&& clrProperty.FindSetterProperty() == null)
{
Expand Down
2 changes: 2 additions & 0 deletions src/EFCore/Metadata/Builders/IConventionPropertyBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -556,6 +556,7 @@ bool CanSetProviderValueComparer(
/// any release. You should only use it directly in your code with extreme caution and knowing that
/// doing so can result in application failures when updating to a new Entity Framework Core release.
/// </summary>
[EntityFrameworkInternal]
IConventionElementTypeBuilder? SetElementType(Type? elementType, bool fromDataAnnotation = false);

/// <summary>
Expand All @@ -564,5 +565,6 @@ bool CanSetProviderValueComparer(
/// any release. You should only use it directly in your code with extreme caution and knowing that
/// doing so can result in application failures when updating to a new Entity Framework Core release.
/// </summary>
[EntityFrameworkInternal]
bool CanSetElementType(Type? elementType, bool fromDataAnnotation = false);
}
Loading

0 comments on commit 60915e7

Please sign in to comment.