Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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
10 changes: 5 additions & 5 deletions src/EFCore.Relational/Design/AnnotationCodeGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,11 @@ public virtual IReadOnlyList<MethodCallCodeFragment> GenerateFluentApiCalls(
annotations.Remove(RelationalAnnotationNames.ContainerColumnType);
}

GenerateSimpleFluentApiCall(
annotations,
RelationalAnnotationNames.JsonPropertyName, nameof(RelationalComplexPropertyBuilderExtensions.HasJsonPropertyName),
methodCallCodeFragments);

methodCallCodeFragments.AddRange(GenerateFluentApiCallsHelper(complexType, annotations, GenerateFluentApi));

return methodCallCodeFragments;
Expand Down Expand Up @@ -397,11 +402,6 @@ public virtual IReadOnlyList<MethodCallCodeFragment> GenerateFluentApiCalls(
{
var methodCallCodeFragments = new List<MethodCallCodeFragment>();

GenerateSimpleFluentApiCall(
annotations,
RelationalAnnotationNames.JsonPropertyName, nameof(RelationalComplexPropertyBuilderExtensions.HasJsonPropertyName),
methodCallCodeFragments);

methodCallCodeFragments.AddRange(GenerateFluentApiCallsHelper(complexProperty, annotations, GenerateFluentApi));

return methodCallCodeFragments;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ namespace Microsoft.EntityFrameworkCore;
/// </remarks>
public static class RelationalComplexPropertyExtensions
{
private static readonly bool UseOldBehavior37009 =
AppContext.TryGetSwitch("Microsoft.EntityFrameworkCore.Issue37009", out var enabled37009) && enabled37009;

/// <summary>
/// Gets the value of JSON property name used for the given complex property of an entity mapped to a JSON column.
/// </summary>
Expand All @@ -23,18 +26,36 @@ public static class RelationalComplexPropertyExtensions
/// <see langword="null" /> is returned for complex properties of entities that are not mapped to a JSON column.
/// </returns>
public static string? GetJsonPropertyName(this IReadOnlyComplexProperty complexProperty)
=> (string?)complexProperty.FindAnnotation(RelationalAnnotationNames.JsonPropertyName)?.Value
?? (complexProperty.DeclaringType.IsMappedToJson() ? complexProperty.Name : null);
{
if (UseOldBehavior37009)
{
return (string?)complexProperty.FindAnnotation(RelationalAnnotationNames.JsonPropertyName)?.Value
?? (complexProperty.DeclaringType.IsMappedToJson() ? complexProperty.Name : null);
}

return complexProperty.ComplexType.GetJsonPropertyName();
}

/// <summary>
/// Sets the value of JSON property name used for the given complex property of an entity mapped to a JSON column.
/// </summary>
/// <param name="complexProperty">The complex property.</param>
/// <param name="name">The name to be used.</param>
public static void SetJsonPropertyName(this IMutableComplexProperty complexProperty, string? name)
=> complexProperty.SetOrRemoveAnnotation(
RelationalAnnotationNames.JsonPropertyName,
Check.NullButNotEmpty(name));
{
if (UseOldBehavior37009)
{
complexProperty.SetOrRemoveAnnotation(
RelationalAnnotationNames.JsonPropertyName,
Check.NullButNotEmpty(name));
}
else
{
complexProperty.ComplexType.SetOrRemoveAnnotation(
RelationalAnnotationNames.JsonPropertyName,
Check.NullButNotEmpty(name));
}
}

/// <summary>
/// Sets the value of JSON property name used for the given complex property of an entity mapped to a JSON column.
Expand All @@ -47,16 +68,33 @@ public static void SetJsonPropertyName(this IMutableComplexProperty complexPrope
this IConventionComplexProperty complexProperty,
string? name,
bool fromDataAnnotation = false)
=> (string?)complexProperty.SetOrRemoveAnnotation(
{
if (UseOldBehavior37009)
{
return (string?)complexProperty.SetOrRemoveAnnotation(
RelationalAnnotationNames.JsonPropertyName,
Check.NullButNotEmpty(name),
fromDataAnnotation)?.Value;
}

return (string?)complexProperty.ComplexType.SetOrRemoveAnnotation(
RelationalAnnotationNames.JsonPropertyName,
Check.NullButNotEmpty(name),
fromDataAnnotation)?.Value;
}

/// <summary>
/// Gets the <see cref="ConfigurationSource" /> for the JSON property name for a given complex property.
/// </summary>
/// <param name="complexProperty">The complex property.</param>
/// <returns>The <see cref="ConfigurationSource" /> for the JSON property name for a given complex property.</returns>
public static ConfigurationSource? GetJsonPropertyNameConfigurationSource(this IConventionComplexProperty complexProperty)
=> complexProperty.FindAnnotation(RelationalAnnotationNames.JsonPropertyName)?.GetConfigurationSource();
{
if (UseOldBehavior37009)
{
return complexProperty.FindAnnotation(RelationalAnnotationNames.JsonPropertyName)?.GetConfigurationSource();
}

return complexProperty.ComplexType.FindAnnotation(RelationalAnnotationNames.JsonPropertyName)?.GetConfigurationSource();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -464,12 +464,19 @@ public static void SetContainerColumnType(this IMutableTypeBase typeBase, string
/// <see langword="null" /> is returned for entities that are not mapped to a JSON column.
/// </returns>
public static string? GetJsonPropertyName(this IReadOnlyTypeBase typeBase)
=> (string?)typeBase.FindAnnotation(RelationalAnnotationNames.JsonPropertyName)?.Value
?? (!typeBase.IsMappedToJson()
? null
: typeBase is IReadOnlyEntityType entityType
? entityType.FindOwnership()!.GetNavigation(pointsToPrincipal: false)!.Name
: ((IReadOnlyComplexType)typeBase).ComplexProperty.Name);
{
var annotation = typeBase.FindAnnotation(RelationalAnnotationNames.JsonPropertyName);
if (annotation != null)
{
return (string?)annotation.Value;
}

return typeBase.FindAnnotation(RelationalAnnotationNames.ContainerColumnName) != null || !typeBase.IsMappedToJson()
? null
: typeBase is IReadOnlyEntityType entityType
? entityType.FindOwnership()!.GetNavigation(pointsToPrincipal: false)!.Name
: ((IReadOnlyComplexType)typeBase).ComplexProperty.Name;
}

#endregion
}
Original file line number Diff line number Diff line change
Expand Up @@ -914,6 +914,16 @@ public virtual void ComplexCollection_can_have_nested_complex_properties_mapped_

var nestedCol3 = complexCollectionProperty1.ComplexType.FindComplexProperty("Collection1")!;
Assert.Equal("CustomNestedCollection3", nestedCol3.GetJsonPropertyName());

// Verify that no complex properties have the JsonPropertyName annotation directly
foreach (var complexProperty in entityType.GetComplexProperties())
{
Assert.Null(complexProperty.FindAnnotation(RelationalAnnotationNames.JsonPropertyName));
foreach (var nestedComplexProperty in complexProperty.ComplexType.GetComplexProperties())
{
Assert.Null(nestedComplexProperty.FindAnnotation(RelationalAnnotationNames.JsonPropertyName));
}
}
}

[ConditionalFact]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -618,6 +618,79 @@ public class JsonEntity

#endregion

#region HasJsonPropertyName

[ConditionalFact]
public virtual async Task HasJsonPropertyName()
{
var contextFactory = await InitializeAsync<Context37009>(
onConfiguring: b => b.ConfigureWarnings(ConfigureWarnings),
onModelCreating: m => m.Entity<Context37009.Entity>().ComplexProperty(e => e.Json, b =>
{
b.ToJson();

b.Property(j => j.String).HasJsonPropertyName("string");

b.ComplexProperty(j => j.Nested, b =>
{
b.HasJsonPropertyName("nested");
b.Property(x => x.Int).HasJsonPropertyName("int");
});

b.ComplexCollection(a => a.NestedCollection, b =>
{
b.HasJsonPropertyName("nested_collection");
b.Property(x => x.Int).HasJsonPropertyName("int");
});
}),
seed: context =>
{
context.Set<Context37009.Entity>().Add(new Context37009.Entity
{
Json = new Context37009.JsonComplexType
{
String = "foo",
Nested = new Context37009.JsonNestedType { Int = 1 },
NestedCollection = [new Context37009.JsonNestedType { Int = 2 }]
}
});

return context.SaveChangesAsync();
});

await using var context = contextFactory.CreateContext();

Assert.Equal(1, await context.Set<Context37009.Entity>().CountAsync(e => e.Json.String == "foo"));
Assert.Equal(1, await context.Set<Context37009.Entity>().CountAsync(e => e.Json.Nested.Int == 1));
Assert.Equal(1, await context.Set<Context37009.Entity>().CountAsync(e => e.Json.NestedCollection.Any(x => x.Int == 2)));
}

protected class Context37009(DbContextOptions options) : DbContext(options)
{
public DbSet<Entity> Entities { get; set; }

public class Entity
{
public int Id { get; set; }
public JsonComplexType Json { get; set; }
}

public class JsonComplexType
{
public string String { get; set; }

public JsonNestedType Nested { get; set; }
public List<JsonNestedType> NestedCollection { get; set; }
}

public class JsonNestedType
{
public int Int { get; set; }
}
}

#endregion HasJsonPropertyName

protected TestSqlLoggerFactory TestSqlLoggerFactory
=> (TestSqlLoggerFactory)ListLoggerFactory;

Expand Down
Loading