Skip to content

Commit 4d458fb

Browse files
authored
Add JSON mapping for complex properties model building support (#36299)
Part of #31252
1 parent 0a01abe commit 4d458fb

File tree

14 files changed

+1192
-202
lines changed

14 files changed

+1192
-202
lines changed
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
namespace Microsoft.EntityFrameworkCore;
5+
6+
/// <summary>
7+
/// Relational database specific extension methods for <see cref="ComplexCollectionBuilder" />.
8+
/// </summary>
9+
/// <remarks>
10+
/// See <see href="https://aka.ms/efcore-docs-modeling">Modeling entity types and relationships</see> for more information and examples.
11+
/// </remarks>
12+
public static class RelationalComplexCollectionBuilderExtensions
13+
{
14+
/// <summary>
15+
/// Configures the complex collection to be stored as a JSON column.
16+
/// </summary>
17+
/// <param name="complexCollectionBuilder">The builder for the complex collection being configured.</param>
18+
/// <param name="jsonColumnName">The name of the JSON column. If not specified, the complex collection name is used.</param>
19+
/// <returns>The same builder instance so that multiple calls can be chained.</returns>
20+
public static ComplexCollectionBuilder ToJson(
21+
this ComplexCollectionBuilder complexCollectionBuilder,
22+
string? jsonColumnName = null)
23+
{
24+
Check.NullButNotEmpty(jsonColumnName);
25+
26+
var complexProperty = complexCollectionBuilder.Metadata;
27+
complexProperty.ComplexType.SetContainerColumnName(jsonColumnName ?? complexProperty.Name);
28+
29+
return complexCollectionBuilder;
30+
}
31+
32+
/// <summary>
33+
/// Configures the complex collection to be stored as a JSON column.
34+
/// </summary>
35+
/// <param name="complexCollectionBuilder">The builder for the complex collection being configured.</param>
36+
/// <param name="jsonColumnName">The name of the JSON column. If not specified, the complex collection name is used.</param>
37+
/// <returns>The same builder instance so that multiple calls can be chained.</returns>
38+
public static ComplexCollectionBuilder<TComplex> ToJson<TComplex>(
39+
this ComplexCollectionBuilder<TComplex> complexCollectionBuilder,
40+
string? jsonColumnName = null)
41+
where TComplex : class
42+
=> (ComplexCollectionBuilder<TComplex>)ToJson((ComplexCollectionBuilder)complexCollectionBuilder, jsonColumnName);
43+
44+
/// <summary>
45+
/// Configures the complex property contained in a JSON column to map to a specific JSON property,
46+
/// rather than using the property name.
47+
/// </summary>
48+
/// <param name="complexCollectionBuilder">The builder for the property being configured.</param>
49+
/// <param name="name">JSON property name to be used.</param>
50+
/// <returns>The same builder instance so that multiple calls can be chained.</returns>
51+
public static ComplexCollectionBuilder HasJsonPropertyName(
52+
this ComplexCollectionBuilder complexCollectionBuilder,
53+
string? name)
54+
{
55+
Check.NullButNotEmpty(name);
56+
57+
complexCollectionBuilder.Metadata.SetJsonPropertyName(name);
58+
59+
return complexCollectionBuilder;
60+
}
61+
62+
/// <summary>
63+
/// Configures the complex property contained in a JSON column to map to a specific JSON property,
64+
/// rather than using the property name.
65+
/// </summary>
66+
/// <param name="complexCollectionBuilder">The builder for the property being configured.</param>
67+
/// <param name="name">JSON property name to be used.</param>
68+
/// <returns>The same builder instance so that multiple calls can be chained.</returns>
69+
public static ComplexCollectionBuilder<TComplex> HasJsonPropertyName<TComplex>(
70+
this ComplexCollectionBuilder<TComplex> complexCollectionBuilder,
71+
string? name)
72+
where TComplex : notnull
73+
=> (ComplexCollectionBuilder<TComplex>)HasJsonPropertyName((ComplexCollectionBuilder)complexCollectionBuilder, name);
74+
}
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
namespace Microsoft.EntityFrameworkCore;
5+
6+
/// <summary>
7+
/// Relational database specific extension methods for <see cref="ComplexPropertyBuilder" />.
8+
/// </summary>
9+
/// <remarks>
10+
/// See <see href="https://aka.ms/efcore-docs-modeling">Modeling entity types and relationships</see> for more information and examples.
11+
/// </remarks>
12+
public static class RelationalComplexPropertyBuilderExtensions
13+
{
14+
/// <summary>
15+
/// Configures the complex property to be stored as a JSON column.
16+
/// </summary>
17+
/// <param name="complexPropertyBuilder">The builder for the complex property being configured.</param>
18+
/// <param name="jsonColumnName">The name of the JSON column. If not specified, the complex property name is used.</param>
19+
/// <returns>The same builder instance so that multiple calls can be chained.</returns>
20+
public static ComplexPropertyBuilder ToJson(
21+
this ComplexPropertyBuilder complexPropertyBuilder,
22+
string? jsonColumnName = null)
23+
{
24+
Check.NullButNotEmpty(jsonColumnName);
25+
26+
var complexProperty = complexPropertyBuilder.Metadata;
27+
28+
complexProperty.ComplexType.SetContainerColumnName(jsonColumnName ?? complexProperty.Name);
29+
30+
return complexPropertyBuilder;
31+
}
32+
33+
/// <summary>
34+
/// Configures the complex property to be stored as a JSON column.
35+
/// </summary>
36+
/// <param name="complexPropertyBuilder">The builder for the complex property being configured.</param>
37+
/// <param name="jsonColumnName">The name of the JSON column. If not specified, the complex property name is used.</param>
38+
/// <returns>The same builder instance so that multiple calls can be chained.</returns>
39+
public static ComplexPropertyBuilder<TComplex> ToJson<TComplex>(
40+
this ComplexPropertyBuilder<TComplex> complexPropertyBuilder,
41+
string? jsonColumnName = null)
42+
where TComplex : class
43+
=> (ComplexPropertyBuilder<TComplex>)ToJson((ComplexPropertyBuilder)complexPropertyBuilder, jsonColumnName);
44+
45+
/// <summary>
46+
/// Configures the complex property of an entity mapped to a JSON column, mapping the complex property to a specific JSON property,
47+
/// rather than using the complex property name.
48+
/// </summary>
49+
/// <param name="complexPropertyBuilder">The builder for the complex property being configured.</param>
50+
/// <param name="name">JSON property name to be used.</param>
51+
/// <returns>The same builder instance so that multiple calls can be chained.</returns>
52+
public static ComplexPropertyBuilder HasJsonPropertyName(
53+
this ComplexPropertyBuilder complexPropertyBuilder,
54+
string? name)
55+
{
56+
Check.NullButNotEmpty(name);
57+
58+
complexPropertyBuilder.Metadata.SetJsonPropertyName(name);
59+
60+
return complexPropertyBuilder;
61+
}
62+
63+
/// <summary>
64+
/// Configures the complex property of an entity mapped to a JSON column, mapping the complex property to a specific JSON property,
65+
/// rather than using the complex property name.
66+
/// </summary>
67+
/// <param name="complexPropertyBuilder">The builder for the complex property being configured.</param>
68+
/// <param name="name">JSON property name to be used.</param>
69+
/// <returns>The same builder instance so that multiple calls can be chained.</returns>
70+
public static ComplexPropertyBuilder<TComplex> HasJsonPropertyName<TComplex>(
71+
this ComplexPropertyBuilder<TComplex> complexPropertyBuilder,
72+
string? name)
73+
where TComplex : notnull
74+
=> (ComplexPropertyBuilder<TComplex>)HasJsonPropertyName((ComplexPropertyBuilder)complexPropertyBuilder, name);
75+
}
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
namespace Microsoft.EntityFrameworkCore;
5+
6+
/// <summary>
7+
/// Complex property extension methods for relational database metadata.
8+
/// </summary>
9+
/// <remarks>
10+
/// See <see href="https://aka.ms/efcore-docs-modeling">Modeling entity types and relationships</see> for more information and examples.
11+
/// </remarks>
12+
public static class RelationalComplexPropertyExtensions
13+
{
14+
/// <summary>
15+
/// Gets the value of JSON property name used for the given complex property of an entity mapped to a JSON column.
16+
/// </summary>
17+
/// <remarks>
18+
/// Unless configured explicitly, complex property name is used.
19+
/// </remarks>
20+
/// <param name="complexProperty">The complex property.</param>
21+
/// <returns>
22+
/// The value for the JSON property used to store the value of this complex property.
23+
/// <see langword="null" /> is returned for complex properties of entities that are not mapped to a JSON column.
24+
/// </returns>
25+
public static string? GetJsonPropertyName(this IReadOnlyComplexProperty complexProperty)
26+
=> (string?)complexProperty.FindAnnotation(RelationalAnnotationNames.JsonPropertyName)?.Value
27+
?? (!complexProperty.DeclaringType.IsMappedToJson() ? null : complexProperty.Name);
28+
29+
/// <summary>
30+
/// Sets the value of JSON property name used for the given complex property of an entity mapped to a JSON column.
31+
/// </summary>
32+
/// <param name="complexProperty">The complex property.</param>
33+
/// <param name="name">The name to be used.</param>
34+
public static void SetJsonPropertyName(this IMutableComplexProperty complexProperty, string? name)
35+
=> complexProperty.SetOrRemoveAnnotation(
36+
RelationalAnnotationNames.JsonPropertyName,
37+
Check.NullButNotEmpty(name));
38+
39+
/// <summary>
40+
/// Sets the value of JSON property name used for the given complex property of an entity mapped to a JSON column.
41+
/// </summary>
42+
/// <param name="complexProperty">The complex property.</param>
43+
/// <param name="name">The name to be used.</param>
44+
/// <param name="fromDataAnnotation">Indicates whether the configuration was specified using a data annotation.</param>
45+
/// <returns>The configured value.</returns>
46+
public static string? SetJsonPropertyName(
47+
this IConventionComplexProperty complexProperty,
48+
string? name,
49+
bool fromDataAnnotation = false)
50+
=> (string?)complexProperty.SetOrRemoveAnnotation(
51+
RelationalAnnotationNames.JsonPropertyName,
52+
Check.NullButNotEmpty(name),
53+
fromDataAnnotation)?.Value;
54+
55+
/// <summary>
56+
/// Gets the <see cref="ConfigurationSource" /> for the JSON property name for a given complex property.
57+
/// </summary>
58+
/// <param name="complexProperty">The complex property.</param>
59+
/// <returns>The <see cref="ConfigurationSource" /> for the JSON property name for a given complex property.</returns>
60+
public static ConfigurationSource? GetJsonPropertyNameConfigurationSource(this IConventionComplexProperty complexProperty)
61+
=> complexProperty.FindAnnotation(RelationalAnnotationNames.JsonPropertyName)?.GetConfigurationSource();
62+
}

src/EFCore.Relational/Extensions/RelationalComplexTypeExtensions.cs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,4 +22,34 @@ public static class RelationalComplexTypeExtensions
2222
=> complexType.FindAnnotation(RelationalAnnotationNames.ContainerColumnName)?.Value is string columnName
2323
? columnName
2424
: complexType.ComplexProperty.DeclaringType.GetContainerColumnName();
25+
26+
/// <summary>
27+
/// Sets the name of the container column to which the complex type is mapped.
28+
/// </summary>
29+
/// <param name="complexType">The complex type to set the container column name for.</param>
30+
/// <param name="columnName">The name to set.</param>
31+
public static void SetContainerColumnName(this IMutableComplexType complexType, string? columnName)
32+
=> complexType.SetOrRemoveAnnotation(RelationalAnnotationNames.ContainerColumnName, columnName);
33+
34+
/// <summary>
35+
/// Sets the name of the container column to which the complex type is mapped.
36+
/// </summary>
37+
/// <param name="complexType">The complex type to set the container column name for.</param>
38+
/// <param name="columnName">The name to set.</param>
39+
/// <param name="fromDataAnnotation">Indicates whether the configuration was specified using a data annotation.</param>
40+
/// <returns>The configured value.</returns>
41+
public static string? SetContainerColumnName(
42+
this IConventionComplexType complexType,
43+
string? columnName,
44+
bool fromDataAnnotation = false)
45+
=> (string?)complexType.SetAnnotation(RelationalAnnotationNames.ContainerColumnName, columnName, fromDataAnnotation)?.Value;
46+
47+
/// <summary>
48+
/// Gets the <see cref="ConfigurationSource" /> for the container column name.
49+
/// </summary>
50+
/// <param name="complexType">The complex type to set the container column name for.</param>
51+
/// <returns>The <see cref="ConfigurationSource" /> for the container column name.</returns>
52+
public static ConfigurationSource? GetContainerColumnNameConfigurationSource(this IConventionComplexType complexType)
53+
=> complexType.FindAnnotation(RelationalAnnotationNames.ContainerColumnName)
54+
?.GetConfigurationSource();
2555
}

0 commit comments

Comments
 (0)