Skip to content

Commit

Permalink
Metadata work for json. Separated from main PR to make the review eas…
Browse files Browse the repository at this point in the history
…ier.

This PR includes:

- builder methods,
- conventions,
- relational model,
- model validation,
- migrations,
- update
  • Loading branch information
maumar committed Jul 29, 2022
1 parent 1ff156c commit 881aae2
Show file tree
Hide file tree
Showing 48 changed files with 3,154 additions and 96 deletions.
125 changes: 124 additions & 1 deletion src/EFCore.Relational/Extensions/RelationalEntityTypeExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// 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;
using Microsoft.EntityFrameworkCore.Metadata.Internal;

// ReSharper disable once CheckNamespace
Expand Down Expand Up @@ -62,7 +63,7 @@ public static class RelationalEntityTypeExtensions

var ownership = entityType.FindOwnership();
if (ownership != null
&& ownership.IsUnique)
&& (ownership.IsUnique || entityType.IsMappedToJson()))
{
return ownership.PrincipalEntityType.GetTableName();
}
Expand Down Expand Up @@ -1390,6 +1391,12 @@ public static IEnumerable<IReadOnlyForeignKey> FindRowInternalForeignKeys(
yield break;
}

var mappedToJson = entityType.IsMappedToJson();
if (mappedToJson)
{
yield break;
}

foreach (var foreignKey in entityType.GetForeignKeys())
{
if (!foreignKey.PrincipalKey.IsPrimaryKey()
Expand Down Expand Up @@ -1855,4 +1862,120 @@ public static IEnumerable<ITrigger> GetDeclaredTriggers(this IEntityType entityT
=> Trigger.GetDeclaredTriggers(entityType).Cast<ITrigger>();

#endregion Trigger

/// <summary>
/// TODO
/// </summary>
public static bool IsMappedToJson(this IEntityType entityType)
=> !string.IsNullOrEmpty(entityType.FindAnnotation(RelationalAnnotationNames.JsonColumnName)?.Value as string);

/// <summary>
/// TODO
/// </summary>
public static bool IsMappedToJson(this IMutableEntityType entityType)
=> !string.IsNullOrEmpty(entityType.FindAnnotation(RelationalAnnotationNames.JsonColumnName)?.Value as string);

/// <summary>
/// TODO
/// </summary>
public static bool IsMappedToJson(this IConventionEntityType entityType)
=> !string.IsNullOrEmpty(entityType.FindAnnotation(RelationalAnnotationNames.JsonColumnName)?.Value as string);

/// <summary>
/// TODO
/// </summary>
public static bool IsMappedToJson(this IReadOnlyEntityType entityType)
=> !string.IsNullOrEmpty(entityType.FindAnnotation(RelationalAnnotationNames.JsonColumnName)?.Value as string);

/// <summary>
/// TODO
/// </summary>
public static void SetJsonColumnName(this IMutableEntityType entityType, string columnName)
=> entityType.SetOrRemoveAnnotation(RelationalAnnotationNames.JsonColumnName, columnName);

/// <summary>
/// TODO
/// </summary>
public static string? SetJsonColumnName(
this IConventionEntityType entityType,
string columnName,
bool fromDataAnnotation = false)
=> (string?)entityType.SetAnnotation(RelationalAnnotationNames.JsonColumnName, columnName, fromDataAnnotation)?.Value;

/// <summary>
/// TODO
/// </summary>
public static ConfigurationSource? GetJsonColumnNameConfigurationSource(this IConventionEntityType entityType)
=> entityType.FindAnnotation(RelationalAnnotationNames.JsonColumnName)
?.GetConfigurationSource();

/// <summary>
/// TODO
/// </summary>
public static string? JsonColumnName(this IEntityType entityType)
=> entityType.FindAnnotation(RelationalAnnotationNames.JsonColumnName)?.Value as string;

/// <summary>
/// TODO
/// </summary>
public static string? JsonColumnName(this IMutableEntityType entityType)
=> entityType.FindAnnotation(RelationalAnnotationNames.JsonColumnName)?.Value as string;

/// <summary>
/// TODO
/// </summary>
public static string? JsonColumnName(this IConventionEntityType entityType)
=> entityType.FindAnnotation(RelationalAnnotationNames.JsonColumnName)?.Value as string;

/// <summary>
/// TODO
/// </summary>
public static string? JsonColumnName(this IReadOnlyEntityType entityType)
=> entityType.FindAnnotation(RelationalAnnotationNames.JsonColumnName)?.Value as string;

/// <summary>
/// TODO
/// </summary>
public static void SetJsonColumnTypeMapping(this IMutableEntityType entityType, RelationalTypeMapping typeMapping)
=> entityType.SetOrRemoveAnnotation(RelationalAnnotationNames.JsonColumnTypeMapping, typeMapping);

/// <summary>
/// TODO
/// </summary>
public static RelationalTypeMapping? SetJsonColumnTypeMapping(
this IConventionEntityType entityType,
RelationalTypeMapping typeMapping,
bool fromDataAnnotation = false)
=> (RelationalTypeMapping?)entityType.SetAnnotation(RelationalAnnotationNames.JsonColumnTypeMapping, typeMapping, fromDataAnnotation)?.Value;

/// <summary>
/// TODO
/// </summary>
public static ConfigurationSource? GetJsonColumnTypeMappingConfigurationSource(this IConventionEntityType entityType)
=> entityType.FindAnnotation(RelationalAnnotationNames.JsonColumnTypeMapping)
?.GetConfigurationSource();

/// <summary>
/// TODO
/// </summary>
public static RelationalTypeMapping? JsonColumnTypeMapping(this IEntityType entityType)
=> entityType.FindAnnotation(RelationalAnnotationNames.JsonColumnTypeMapping)?.Value as RelationalTypeMapping;

/// <summary>
/// TODO
/// </summary>
public static RelationalTypeMapping? JsonColumnTypeMapping(this IMutableEntityType entityType)
=> entityType.FindAnnotation(RelationalAnnotationNames.JsonColumnTypeMapping)?.Value as RelationalTypeMapping;

/// <summary>
/// TODO
/// </summary>
public static RelationalTypeMapping? JsonColumnTypeMapping(this IConventionEntityType entityType)
=> entityType.FindAnnotation(RelationalAnnotationNames.JsonColumnTypeMapping)?.Value as RelationalTypeMapping;

/// <summary>
/// TODO
/// </summary>
public static RelationalTypeMapping? JsonColumnTypeMapping(this IReadOnlyEntityType entityType)
=> entityType.FindAnnotation(RelationalAnnotationNames.JsonColumnTypeMapping)?.Value as RelationalTypeMapping;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
// 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="NavigationBuilder" />.
/// </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 RelationalNavigationBuilderExtensions
{
/// <summary>
/// TODO
/// </summary>
public static NavigationBuilder HasJsonElementName(
this NavigationBuilder navigationBuilder,
string? name)
{
Check.NullButNotEmpty(name, nameof(name));

navigationBuilder.Metadata.SetJsonElementName(name);

return navigationBuilder;
}

/// <summary>
/// TODO
/// </summary>
public static NavigationBuilder<TSource, TTarget> HasJsonElementName<TSource, TTarget>(
this NavigationBuilder<TSource, TTarget> navigationBuilder,
string? name)
where TSource : class
where TTarget : class
=> (NavigationBuilder<TSource, TTarget>)HasJsonElementName((NavigationBuilder)navigationBuilder, name);

/// <summary>
/// TODO
/// </summary>
public static IConventionNavigationBuilder? HasJsonElementName(
this IConventionNavigationBuilder navigationBuilder,
string? name,
bool fromDataAnnotation = false)
{
if (!navigationBuilder.CanSetJsonElementName(name, fromDataAnnotation))
{
return null;
}

navigationBuilder.Metadata.SetJsonElementName(name, fromDataAnnotation);

return navigationBuilder;
}

/// <summary>
/// TODO
/// </summary>
public static bool CanSetJsonElementName(
this IConventionNavigationBuilder navigationBuilder,
string? name,
bool fromDataAnnotation = false)
=> navigationBuilder.CanSetAnnotation(RelationalAnnotationNames.JsonElementName, name, fromDataAnnotation);
}
49 changes: 49 additions & 0 deletions src/EFCore.Relational/Extensions/RelationalNavigationExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// 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>
/// Navigation 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 RelationalNavigationExtensions
{
/// <summary>
/// TODO
/// </summary>
public static string JsonElementName(this IReadOnlyNavigationBase navigation)
=> (string?)navigation.FindAnnotation(RelationalAnnotationNames.JsonElementName)?.Value ?? navigation.Name;

/// <summary>
/// TODO
/// </summary>
public static void SetJsonElementName(this IMutableNavigationBase navigation, string? name)
=> navigation.SetOrRemoveAnnotation(
RelationalAnnotationNames.JsonElementName,
Check.NullButNotEmpty(name, nameof(name)));

/// <summary>
/// TODO
/// </summary>
public static string? SetJsonElementName(
this IConventionNavigationBase navigation,
string? name,
bool fromDataAnnotation = false)
{
navigation.SetOrRemoveAnnotation(
RelationalAnnotationNames.JsonElementName,
Check.NullButNotEmpty(name, nameof(name)),
fromDataAnnotation);

return name;
}

/// <summary>
/// TODO
/// </summary>
public static ConfigurationSource? GetJsonElementNameConfigurationSource(this IConventionNavigationBase navigation)
=> navigation.FindAnnotation(RelationalAnnotationNames.JsonElementName)?.GetConfigurationSource();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// 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="OwnedNavigationBuilder" />.
/// </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 RelationalOwnedNavigationBuilderExtensions
{
/// <summary>
/// TODO
/// </summary>
public static OwnedNavigationBuilder<TOwnerEntity, TDependentEntity> ToJson<TOwnerEntity, TDependentEntity>(
this OwnedNavigationBuilder<TOwnerEntity, TDependentEntity> builder,
string jsonColumnName)
where TOwnerEntity : class
where TDependentEntity : class
{
builder.OwnedEntityType.SetJsonColumnName(jsonColumnName);

return builder;
}

/// <summary>
/// TODO
/// </summary>
public static OwnedNavigationBuilder ToJson(
this OwnedNavigationBuilder builder,
string? jsonColumnName = null)
{
if (jsonColumnName == null)
{
// TODO: is this guaranteed to be false here, or should we be more defensive?
var navigationName = builder.Metadata.GetNavigation(pointsToPrincipal: false)!.Name;
builder.OwnedEntityType.SetJsonColumnName(navigationName);
}
else
{
builder.OwnedEntityType.SetJsonColumnName(jsonColumnName);
}

return builder;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -1035,4 +1035,53 @@ public static bool CanSetCollation(
string? collation,
bool fromDataAnnotation = false)
=> propertyBuilder.CanSetAnnotation(RelationalAnnotationNames.Collation, collation, fromDataAnnotation);

/// <summary>
/// TODO
/// </summary>
public static PropertyBuilder HasJsonElementName(
this PropertyBuilder propertyBuilder,
string? name)
{
Check.NullButNotEmpty(name, nameof(name));

propertyBuilder.Metadata.SetJsonElementName(name);

return propertyBuilder;
}

/// <summary>
/// TODO
/// </summary>
public static PropertyBuilder<TProperty> HasJsonElementName<TProperty>(
this PropertyBuilder<TProperty> propertyBuilder,
string? name)
=> (PropertyBuilder<TProperty>)HasJsonElementName((PropertyBuilder)propertyBuilder, name);

/// <summary>
/// TODO
/// </summary>
public static IConventionPropertyBuilder? HasJsonElementName(
this IConventionPropertyBuilder propertyBuilder,
string? name,
bool fromDataAnnotation = false)
{
if (!propertyBuilder.CanSetJsonElementName(name, fromDataAnnotation))
{
return null;
}

propertyBuilder.Metadata.SetJsonElementName(name, fromDataAnnotation);

return propertyBuilder;
}

/// <summary>
/// TODO
/// </summary>
public static bool CanSetJsonElementName(
this IConventionPropertyBuilder propertyBuilder,
string? name,
bool fromDataAnnotation = false)
=> propertyBuilder.CanSetAnnotation(RelationalAnnotationNames.JsonElementName, name, fromDataAnnotation);
}
Loading

0 comments on commit 881aae2

Please sign in to comment.