Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Metadata for primitive collection mapping #31351

Merged
merged 3 commits into from
Aug 10, 2023
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
@@ -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
ajcvickers marked this conversation as resolved.
Show resolved Hide resolved
{
/// <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
Loading