diff --git a/src/EFCore.Cosmos/Extensions/CosmosEntityTypeExtensions.cs b/src/EFCore.Cosmos/Extensions/CosmosEntityTypeExtensions.cs
index ad0dcabff9e..f162fb711ef 100644
--- a/src/EFCore.Cosmos/Extensions/CosmosEntityTypeExtensions.cs
+++ b/src/EFCore.Cosmos/Extensions/CosmosEntityTypeExtensions.cs
@@ -72,8 +72,12 @@ public static void SetContainer(this IMutableEntityType entityType, string? name
/// The entity type to get the containing property name for.
/// The name of the parent property to which the entity type is mapped.
public static string? GetContainingPropertyName(this IReadOnlyEntityType entityType)
- => entityType[CosmosAnnotationNames.PropertyName] as string
- ?? GetDefaultContainingPropertyName(entityType);
+ {
+ var propertyName = entityType.FindAnnotation(CosmosAnnotationNames.PropertyName);
+ return propertyName == null
+ ? GetDefaultContainingPropertyName(entityType)
+ : (string?)propertyName.Value;
+ }
private static string? GetDefaultContainingPropertyName(IReadOnlyEntityType entityType)
=> entityType.FindOwnership() is IReadOnlyForeignKey ownership
@@ -198,7 +202,7 @@ public static void SetPartitionKeyPropertyName(this IMutableEntityType entityTyp
public static IReadOnlyList GetPartitionKeyPropertyNames(this IReadOnlyEntityType entityType)
=> entityType[CosmosAnnotationNames.PartitionKeyNames] as IReadOnlyList
?? entityType.BaseType?.GetPartitionKeyPropertyNames()
- ?? Array.Empty();
+ ?? [];
///
/// Sets the names of the properties that are used to store the hierarchical partition key.
diff --git a/src/EFCore.Relational/Extensions/RelationalEntityTypeExtensions.cs b/src/EFCore.Relational/Extensions/RelationalEntityTypeExtensions.cs
index 93beae7be86..8cee65a5187 100644
--- a/src/EFCore.Relational/Extensions/RelationalEntityTypeExtensions.cs
+++ b/src/EFCore.Relational/Extensions/RelationalEntityTypeExtensions.cs
@@ -1606,8 +1606,12 @@ public static void SetContainerColumnName(this IMutableEntityType entityType, st
/// The entity type to get the container column name for.
/// The container column name to which the entity type is mapped.
public static string? GetContainerColumnName(this IReadOnlyEntityType entityType)
- => entityType.FindAnnotation(RelationalAnnotationNames.ContainerColumnName)?.Value as string
- ?? entityType.FindOwnership()?.PrincipalEntityType.GetContainerColumnName();
+ {
+ var containerColumnName = entityType.FindAnnotation(RelationalAnnotationNames.ContainerColumnName);
+ return containerColumnName == null
+ ? entityType.FindOwnership()?.PrincipalEntityType.GetContainerColumnName()
+ : (string?)containerColumnName.Value;
+ }
///
/// Sets the column type to use for the container column to which the entity type is mapped.
@@ -1720,8 +1724,14 @@ public static void SetContainerColumnTypeMapping(this IMutableEntityType entityT
/// is returned for entities that are not mapped to a JSON column.
///
public static string? GetJsonPropertyName(this IReadOnlyEntityType entityType)
- => (string?)entityType.FindAnnotation(RelationalAnnotationNames.JsonPropertyName)?.Value
- ?? (!entityType.IsMappedToJson() ? null : entityType.FindOwnership()!.GetNavigation(pointsToPrincipal: false)!.Name);
+ {
+ var propertyName = entityType.FindAnnotation(RelationalAnnotationNames.JsonPropertyName);
+ return propertyName == null
+ ? (entityType.IsMappedToJson()
+ ? entityType.FindOwnership()!.GetNavigation(pointsToPrincipal: false)!.Name
+ : null)
+ : (string?)propertyName.Value;
+ }
///
/// Sets the value of JSON property name used for the given entity mapped to a JSON column.
diff --git a/src/EFCore.Relational/Infrastructure/RelationalModelValidator.cs b/src/EFCore.Relational/Infrastructure/RelationalModelValidator.cs
index ebd72d633df..69ed1618137 100644
--- a/src/EFCore.Relational/Infrastructure/RelationalModelValidator.cs
+++ b/src/EFCore.Relational/Infrastructure/RelationalModelValidator.cs
@@ -2833,8 +2833,13 @@ protected virtual void ValidateJsonEntityProperties(
IEntityType jsonEntityType)
{
var jsonPropertyNames = new List();
- foreach (var property in jsonEntityType.GetDeclaredProperties().Where(p => !string.IsNullOrEmpty(p.GetJsonPropertyName())))
+ foreach (var property in jsonEntityType.GetDeclaredProperties())
{
+ if (string.IsNullOrEmpty(property.GetJsonPropertyName()))
+ {
+ continue;
+ }
+
if (property.TryGetDefaultValue(out var _))
{
throw new InvalidOperationException(
@@ -2857,6 +2862,12 @@ protected virtual void ValidateJsonEntityProperties(
foreach (var navigation in jsonEntityType.GetDeclaredNavigations())
{
+ if (!navigation.TargetEntityType.IsMappedToJson()
+ || navigation.IsOnDependent)
+ {
+ continue;
+ }
+
var jsonPropertyName = navigation.TargetEntityType.GetJsonPropertyName()!;
if (!jsonPropertyNames.Contains(jsonPropertyName))
{
diff --git a/test/EFCore.SqlServer.FunctionalTests/ModelBuilding/SqlServerModelBuilderTestBase.cs b/test/EFCore.SqlServer.FunctionalTests/ModelBuilding/SqlServerModelBuilderTestBase.cs
index 5f76da6288e..9b20c495e9e 100644
--- a/test/EFCore.SqlServer.FunctionalTests/ModelBuilding/SqlServerModelBuilderTestBase.cs
+++ b/test/EFCore.SqlServer.FunctionalTests/ModelBuilding/SqlServerModelBuilderTestBase.cs
@@ -1633,8 +1633,11 @@ public virtual void Json_entity_with_nested_structure_same_property_names()
x => x.OwnedCollection2, bb =>
{
bb.ToJson("col2");
- bb.OwnsOne(x => x.Reference1);
- bb.OwnsOne(x => x.Reference2);
+ bb.OwnsOne(x => x.Reference1)
+ .HasAnnotation(RelationalAnnotationNames.JsonPropertyName, null);
+ bb.OwnsOne(x => x.Reference2)
+ .ToTable("Ref2")
+ .HasAnnotation(RelationalAnnotationNames.ContainerColumnName, null);
bb.OwnsMany(x => x.Collection1);
bb.OwnsMany(x => x.Collection2);
});
@@ -1642,36 +1645,49 @@ public virtual void Json_entity_with_nested_structure_same_property_names()
var model = modelBuilder.FinalizeModel();
var outerOwnedEntities = model.FindEntityTypes(typeof(OwnedEntityExtraLevel));
- Assert.Equal(4, outerOwnedEntities.Count());
+
+ Assert.Collection(outerOwnedEntities,
+ e => Assert.Equal("col1", e.GetContainerColumnName()),
+ e => Assert.Equal("col2", e.GetContainerColumnName()),
+ e => Assert.Equal("ref1", e.GetContainerColumnName()),
+ e => Assert.Equal("ref2", e.GetContainerColumnName()));
foreach (var outerOwnedEntity in outerOwnedEntities)
{
Assert.Equal("Date", outerOwnedEntity.GetProperty("Date").GetJsonPropertyName());
Assert.Equal("Fraction", outerOwnedEntity.GetProperty("Fraction").GetJsonPropertyName());
Assert.Equal("Enum", outerOwnedEntity.GetProperty("Enum").GetJsonPropertyName());
- Assert.Equal(
- "Reference1",
- outerOwnedEntity.GetNavigations().Single(n => n.Name == "Reference1").TargetEntityType.GetJsonPropertyName());
- Assert.Equal(
- "Reference2",
- outerOwnedEntity.GetNavigations().Single(n => n.Name == "Reference2").TargetEntityType.GetJsonPropertyName());
- Assert.Equal(
- "Collection1",
- outerOwnedEntity.GetNavigations().Single(n => n.Name == "Collection1").TargetEntityType.GetJsonPropertyName());
- Assert.Equal(
- "Collection2",
- outerOwnedEntity.GetNavigations().Single(n => n.Name == "Collection2").TargetEntityType.GetJsonPropertyName());
- }
- var ownedEntities = model.FindEntityTypes(typeof(OwnedEntity));
- Assert.Equal(16, ownedEntities.Count());
+ var nestedOwnedTypes = outerOwnedEntity.GetNavigations().Select(n => n.TargetEntityType).ToList();
+ Assert.Collection(nestedOwnedTypes,
+ e => Assert.Equal("Collection1", e.GetJsonPropertyName()),
+ e => Assert.Equal("Collection2", e.GetJsonPropertyName()),
+ e => Assert.Equal(outerOwnedEntity.GetContainerColumnName() == "col2" ? null : "Reference1",
+ e.GetJsonPropertyName()),
+ e => Assert.Equal(outerOwnedEntity.GetContainerColumnName() == "col2" ? null : "Reference2",
+ e.GetJsonPropertyName()));
+
+ Assert.Collection(nestedOwnedTypes,
+ e => Assert.Equal(outerOwnedEntity.GetContainerColumnName(), e.GetContainerColumnName()),
+ e => Assert.Equal(outerOwnedEntity.GetContainerColumnName(), e.GetContainerColumnName()),
+ e => Assert.Equal(outerOwnedEntity.GetContainerColumnName(), e.GetContainerColumnName()),
+ e => Assert.Equal(outerOwnedEntity.GetContainerColumnName() == "col2" ?
+ null : outerOwnedEntity.GetContainerColumnName(), e.GetContainerColumnName()));
+
+ foreach (var ownedEntity in nestedOwnedTypes)
+ {
+ if (ownedEntity.GetContainerColumnName() == null)
+ {
+ continue;
+ }
- foreach (var ownedEntity in ownedEntities)
- {
- Assert.Equal("Date", ownedEntity.GetProperty("Date").GetJsonPropertyName());
- Assert.Equal("Fraction", ownedEntity.GetProperty("Fraction").GetJsonPropertyName());
- Assert.Equal("Enum", ownedEntity.GetProperty("Enum").GetJsonPropertyName());
+ Assert.Equal("Date", ownedEntity.GetProperty("Date").GetJsonPropertyName());
+ Assert.Equal("Fraction", ownedEntity.GetProperty("Fraction").GetJsonPropertyName());
+ Assert.Equal("Enum", ownedEntity.GetProperty("Enum").GetJsonPropertyName());
+ }
}
+
+ Assert.Equal(16, model.FindEntityTypes(typeof(OwnedEntity)).Count());
}
[ConditionalFact]
@@ -2047,62 +2063,6 @@ public virtual void Json_entity_and_normal_owned_can_exist_side_to_side_on_same_
Assert.Equal(2, ownedEntities.Where(e => e.IsMappedToJson()).Count());
Assert.Equal(2, ownedEntities.Where(e => e.IsOwned() && !e.IsMappedToJson()).Count());
}
-
- [ConditionalFact]
- public virtual void Json_entity_with_nested_structure_same_property_names_()
- {
- var modelBuilder = CreateModelBuilder();
- modelBuilder.Entity(
- b =>
- {
- b.OwnsOne(
- x => x.OwnedReference1, bb =>
- {
- bb.ToJson("ref1");
- bb.OwnsOne(x => x.Reference1);
- bb.OwnsOne(x => x.Reference2);
- bb.OwnsMany(x => x.Collection1);
- bb.OwnsMany(x => x.Collection2);
- });
-
- b.OwnsOne(
- x => x.OwnedReference2, bb =>
- {
- bb.ToJson("ref2");
- bb.OwnsOne(x => x.Reference1);
- bb.OwnsOne(x => x.Reference2);
- bb.OwnsMany(x => x.Collection1);
- bb.OwnsMany(x => x.Collection2);
- });
-
- b.OwnsMany(
- x => x.OwnedCollection1, bb =>
- {
- bb.ToJson("col1");
- bb.OwnsOne(x => x.Reference1);
- bb.OwnsOne(x => x.Reference2);
- bb.OwnsMany(x => x.Collection1);
- bb.OwnsMany(x => x.Collection2);
- });
-
- b.OwnsMany(
- x => x.OwnedCollection2, bb =>
- {
- bb.ToJson("col2");
- bb.OwnsOne(x => x.Reference1);
- bb.OwnsOne(x => x.Reference2);
- bb.OwnsMany(x => x.Collection1);
- bb.OwnsMany(x => x.Collection2);
- });
- });
-
- var model = modelBuilder.FinalizeModel();
- var outerOwnedEntities = model.FindEntityTypes(typeof(OwnedEntityExtraLevel));
- Assert.Equal(4, outerOwnedEntities.Count());
-
- var ownedEntities = model.FindEntityTypes(typeof(OwnedEntity));
- Assert.Equal(16, ownedEntities.Count());
- }
}
public class SqlServerModelBuilderFixture : RelationalModelBuilderFixture