Skip to content

Commit

Permalink
Metadata for primitive collection mapping (#31351)
Browse files Browse the repository at this point in the history
  • Loading branch information
ajcvickers authored Aug 10, 2023
1 parent 0dd62a2 commit 5b556d3
Show file tree
Hide file tree
Showing 100 changed files with 13,007 additions and 2,145 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

namespace Microsoft.EntityFrameworkCore;

/// <summary>
/// Cosmos-specific extension methods for <see cref="PrimitiveCollectionBuilder" />.
/// </summary>
/// <remarks>
/// See <see href="https://aka.ms/efcore-docs-modeling">Modeling entity types and relationships</see>, and
/// <see href="https://aka.ms/efcore-docs-cosmos">Accessing Azure Cosmos DB with EF Core</see> for more information and examples.
/// </remarks>
public static class CosmosPrimitiveCollectionBuilderExtensions
{
/// <summary>
/// Configures the property name that the property is mapped to when targeting Azure Cosmos.
/// </summary>
/// <remarks>
/// <para>
/// If an empty string is supplied, the property will not be persisted.
/// </para>
/// <para>
/// See <see href="https://aka.ms/efcore-docs-modeling">Modeling entity types and relationships</see>, and
/// <see href="https://aka.ms/efcore-docs-cosmos">Accessing Azure Cosmos DB with EF Core</see> for more information and examples.
/// </para>
/// </remarks>
/// <param name="primitiveCollectionBuilder">The builder for the property being configured.</param>
/// <param name="name">The name of the property.</param>
/// <returns>The same builder instance so that multiple calls can be chained.</returns>
public static PrimitiveCollectionBuilder ToJsonProperty(
this PrimitiveCollectionBuilder primitiveCollectionBuilder,
string name)
{
Check.NotNull(name, nameof(name));

primitiveCollectionBuilder.Metadata.SetJsonPropertyName(name);

return primitiveCollectionBuilder;
}

/// <summary>
/// Configures the property name that the property is mapped to when targeting Azure Cosmos.
/// </summary>
/// <remarks>
/// See <see href="https://aka.ms/efcore-docs-modeling">Modeling entity types and relationships</see>, and
/// <see href="https://aka.ms/efcore-docs-cosmos">Accessing Azure Cosmos DB with EF Core</see> for more information and examples.
/// </remarks>
/// <typeparam name="TProperty">The type of the property being configured.</typeparam>
/// <param name="primitiveCollectionBuilder">The builder for the property being configured.</param>
/// <param name="name">The name of the property.</param>
/// <returns>The same builder instance so that multiple calls can be chained.</returns>
public static PrimitiveCollectionBuilder<TProperty> ToJsonProperty<TProperty>(
this PrimitiveCollectionBuilder<TProperty> primitiveCollectionBuilder,
string name)
=> (PrimitiveCollectionBuilder<TProperty>)ToJsonProperty((PrimitiveCollectionBuilder)primitiveCollectionBuilder, name);
}

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using Microsoft.EntityFrameworkCore.Metadata.Internal;

// ReSharper disable once CheckNamespace
namespace Microsoft.EntityFrameworkCore;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

namespace Microsoft.EntityFrameworkCore;

/// <summary>
/// Relational database specific extension methods for <see cref="ElementTypeBuilder" />.
/// </summary>
/// <remarks>
/// See <see href="https://aka.ms/efcore-docs-modeling">Modeling entity types and relationships</see> for more information and examples.
/// </remarks>
public static class RelationalElementTypeBuilderExtensions
{
/// <summary>
/// Configures the data type of the elements of the collection.
/// </summary>
/// <remarks>
/// See <see href="https://aka.ms/efcore-docs-modeling">Modeling entity types and relationships</see> for more information and examples.
/// </remarks>
/// <param name="elementTypeBuilder">The builder for the elements being configured.</param>
/// <param name="typeName">The name of the data type of the elements.</param>
/// <returns>The same builder instance so that multiple calls can be chained.</returns>
public static ElementTypeBuilder HasStoreType(
this ElementTypeBuilder elementTypeBuilder,
string? typeName)
{
Check.NullButNotEmpty(typeName, nameof(typeName));

elementTypeBuilder.Metadata.SetStoreType(typeName);

return elementTypeBuilder;
}

/// <summary>
/// Configures the data type of the elements of the collection.
/// </summary>
/// <remarks>
/// See <see href="https://aka.ms/efcore-docs-modeling">Modeling entity types and relationships</see> for more information and examples.
/// </remarks>
/// <param name="elementTypeBuilder"> builder for the elements being configured.</param>
/// <param name="typeName">The name of the data type of the elements.</param>
/// <param name="fromDataAnnotation">Indicates whether the configuration was specified using a data annotation.</param>
/// <returns>The same builder instance if the configuration was applied, <see langword="null" /> otherwise.</returns>
public static IConventionElementTypeBuilder? HasStoreType(
this IConventionElementTypeBuilder elementTypeBuilder,
string? typeName,
bool fromDataAnnotation = false)
{
if (!elementTypeBuilder.CanSetStoreType(typeName, fromDataAnnotation))
{
return null;
}

elementTypeBuilder.Metadata.SetStoreType(typeName, fromDataAnnotation);
return elementTypeBuilder;
}

/// <summary>
/// Returns a value indicating whether the given data type can be set for the elements.
/// </summary>
/// <remarks>
/// See <see href="https://aka.ms/efcore-docs-modeling">Modeling entity types and relationships</see> for more information and examples.
/// </remarks>
/// <param name="elementTypeBuilder"> builder for the elements being configured.</param>
/// <param name="typeName">The name of the data type of the elements.</param>
/// <param name="fromDataAnnotation">Indicates whether the configuration was specified using a data annotation.</param>
/// <returns><see langword="true" /> if the given data type can be set for the property.</returns>
public static bool CanSetStoreType(
this IConventionElementTypeBuilder elementTypeBuilder,
string? typeName,
bool fromDataAnnotation = false)
=> elementTypeBuilder.CanSetAnnotation(RelationalAnnotationNames.StoreType, typeName, fromDataAnnotation);

/// <summary>
/// Configures the elements as capable of storing only fixed-length data, such as strings.
/// </summary>
/// <remarks>
/// See <see href="https://aka.ms/efcore-docs-modeling">Modeling entity types and relationships</see> for more information and examples.
/// </remarks>
/// <param name="elementTypeBuilder">The builder for the elements being configured.</param>
/// <param name="fixedLength">A value indicating whether the elements are constrained to fixed length values.</param>
/// <returns>The same builder instance so that multiple configuration calls can be chained.</returns>
public static ElementTypeBuilder IsFixedLength(
this ElementTypeBuilder elementTypeBuilder,
bool fixedLength = true)
{
elementTypeBuilder.Metadata.SetIsFixedLength(fixedLength);

return elementTypeBuilder;
}

/// <summary>
/// Configures the elements as capable of storing only fixed-length data, such as strings.
/// </summary>
/// <remarks>
/// See <see href="https://aka.ms/efcore-docs-modeling">Modeling entity types and relationships</see> for more information and examples.
/// </remarks>
/// <param name="elementTypeBuilder"> builder for the elements being configured.</param>
/// <param name="fixedLength">A value indicating whether the elements are constrained to fixed length values.</param>
/// <param name="fromDataAnnotation">Indicates whether the configuration was specified using a data annotation.</param>
/// <returns> The same builder instance if the configuration was applied, <see langword="null" /> otherwise.</returns>
public static IConventionElementTypeBuilder? IsFixedLength(
this IConventionElementTypeBuilder elementTypeBuilder,
bool? fixedLength,
bool fromDataAnnotation = false)
{
if (!elementTypeBuilder.CanSetFixedLength(fixedLength, fromDataAnnotation))
{
return null;
}

elementTypeBuilder.Metadata.SetIsFixedLength(fixedLength, fromDataAnnotation);
return elementTypeBuilder;
}

/// <summary>
/// Returns a value indicating whether the elements can be configured as being fixed length or not.
/// </summary>
/// <remarks>
/// See <see href="https://aka.ms/efcore-docs-modeling">Modeling entity types and relationships</see> for more information and examples.
/// </remarks>
/// <param name="elementTypeBuilder"> builder for the elements being configured.</param>
/// <param name="fixedLength">A value indicating whether the elements are constrained to fixed length values.</param>
/// <param name="fromDataAnnotation">Indicates whether the configuration was specified using a data annotation.</param>
/// <returns><see langword="true" /> if the elements can be configured as being fixed length or not.</returns>
public static bool CanSetFixedLength(
this IConventionElementTypeBuilder elementTypeBuilder,
bool? fixedLength,
bool fromDataAnnotation = false)
=> elementTypeBuilder.CanSetAnnotation(RelationalAnnotationNames.IsFixedLength, fixedLength, fromDataAnnotation);
}
133 changes: 133 additions & 0 deletions src/EFCore.Relational/Extensions/RelationalElementTypeExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

namespace Microsoft.EntityFrameworkCore;

/// <summary>
/// <see cref="IElementType" /> extension methods for relational database metadata.
/// </summary>
/// <remarks>
/// See <see href="https://aka.ms/efcore-docs-modeling">Modeling entity types and relationships</see> for more information and examples.
/// </remarks>
public static class RelationalElementTypeExtensions
{
/// <summary>
/// Returns the database type of the elements, or <see langword="null" /> if the database type could not be found.
/// </summary>
/// <param name="elementType">The element.</param>
/// <returns>
/// The database type of the elements, or <see langword="null" /> if the database type could not be found.
/// </returns>
public static string? GetStoreType(this IReadOnlyElementType elementType)
=> (string?)(elementType.FindAnnotation(RelationalAnnotationNames.StoreType)?.Value
?? elementType.FindRelationalTypeMapping()?.StoreType);

/// <summary>
/// Returns the database type of the elements.
/// </summary>
/// <param name="elementType">The element.</param>
/// <returns>The database type of the elements.</returns>
public static string GetStoreType(this IElementType elementType)
=> ((IReadOnlyElementType)elementType).GetStoreType()!;

/// <summary>
/// Sets the database type of the elements.
/// </summary>
/// <param name="elementType">The element.</param>
/// <param name="value">The value to set.</param>
public static void SetStoreType(this IMutableElementType elementType, string? value)
=> elementType.SetOrRemoveAnnotation(
RelationalAnnotationNames.StoreType,
Check.NullButNotEmpty(value, nameof(value)));

/// <summary>
/// Sets the database type of the elements.
/// </summary>
/// <param name="elementType">The element.</param>
/// <param name="value">The value to set.</param>
/// <param name="fromDataAnnotation">Indicates whether the configuration was specified using a data annotation.</param>
/// <returns>The configured value.</returns>
public static string? SetStoreType(
this IConventionElementType elementType,
string? value,
bool fromDataAnnotation = false)
=> (string?)elementType.SetOrRemoveAnnotation(
RelationalAnnotationNames.StoreType,
Check.NullButNotEmpty(value, nameof(value)),
fromDataAnnotation)?.Value;

/// <summary>
/// Gets the <see cref="ConfigurationSource" /> for the database type.
/// </summary>
/// <param name="elementType">The element.</param>
/// <returns>The <see cref="ConfigurationSource" /> for the column name.</returns>
public static ConfigurationSource? GetStoreTypeConfigurationSource(this IConventionElementType elementType)
=> elementType.FindAnnotation(RelationalAnnotationNames.StoreType)?.GetConfigurationSource();

/// <summary>
/// Returns a flag indicating whether the elements are capable of storing only fixed-length data, such as strings.
/// </summary>
/// <param name="elementType">The element.</param>
/// <returns>A flag indicating whether the elements arecapable of storing only fixed-length data, such as strings.</returns>
public static bool? IsFixedLength(this IReadOnlyElementType elementType)
=> (bool?)elementType.FindAnnotation(RelationalAnnotationNames.IsFixedLength)?.Value;

/// <summary>
/// Returns a flag indicating whether the elements are capable of storing only fixed-length data, such as strings.
/// </summary>
/// <param name="elementType">The element.</param>
/// <param name="storeObject">The identifier of the table-like store object containing the column.</param>
/// <returns>A flag indicating whether the elements are capable of storing only fixed-length data, such as strings.</returns>
public static bool? IsFixedLength(this IReadOnlyElementType elementType, in StoreObjectIdentifier storeObject)
=> (bool?)elementType.FindAnnotation(RelationalAnnotationNames.IsFixedLength)?.Value;

/// <summary>
/// Sets a flag indicating whether the elements are capable of storing only fixed-length data, such as strings.
/// </summary>
/// <param name="elementType">The element.</param>
/// <param name="fixedLength">A value indicating whether the elements are constrained to fixed length values.</param>
public static void SetIsFixedLength(this IMutableElementType elementType, bool? fixedLength)
=> elementType.SetOrRemoveAnnotation(RelationalAnnotationNames.IsFixedLength, fixedLength);

/// <summary>
/// Sets a flag indicating whether the elements are capable of storing only fixed-length data, such as strings.
/// </summary>
/// <param name="elementType">The element.</param>
/// <param name="fixedLength">A value indicating whether the element are constrained to fixed length values.</param>
/// <param name="fromDataAnnotation">Indicates whether the configuration was specified using a data annotation.</param>
/// <returns>The configured value.</returns>
public static bool? SetIsFixedLength(
this IConventionElementType elementType,
bool? fixedLength,
bool fromDataAnnotation = false)
=> (bool?)elementType.SetOrRemoveAnnotation(
RelationalAnnotationNames.IsFixedLength,
fixedLength,
fromDataAnnotation)?.Value;

/// <summary>
/// Gets the <see cref="ConfigurationSource" /> for <see cref="IsFixedLength(IReadOnlyElementType)" />.
/// </summary>
/// <param name="elementType">The element.</param>
/// <returns>The <see cref="ConfigurationSource" /> for <see cref="IsFixedLength(IReadOnlyElementType)" />.</returns>
public static ConfigurationSource? GetIsFixedLengthConfigurationSource(this IConventionElementType elementType)
=> elementType.FindAnnotation(RelationalAnnotationNames.IsFixedLength)?.GetConfigurationSource();

/// <summary>
/// Returns the <see cref="RelationalTypeMapping" /> for the given element on a finalized model.
/// </summary>
/// <param name="elementType">The element.</param>
/// <returns>The type mapping.</returns>
[DebuggerStepThrough]
public static RelationalTypeMapping GetRelationalTypeMapping(this IReadOnlyElementType elementType)
=> (RelationalTypeMapping)elementType.GetTypeMapping();

/// <summary>
/// Returns the <see cref="RelationalTypeMapping" /> for the given element on a finalized model.
/// </summary>
/// <param name="elementType">The element.</param>
/// <returns>The type mapping, or <see langword="null" /> if none was found.</returns>
[DebuggerStepThrough]
public static RelationalTypeMapping? FindRelationalTypeMapping(this IReadOnlyElementType elementType)
=> (RelationalTypeMapping?)elementType.FindTypeMapping();
}
Loading

0 comments on commit 5b556d3

Please sign in to comment.