diff --git a/src/EFCore.Relational/Infrastructure/RelationalModelValidator.cs b/src/EFCore.Relational/Infrastructure/RelationalModelValidator.cs
index f64fce248fa..e33d78bc4f8 100644
--- a/src/EFCore.Relational/Infrastructure/RelationalModelValidator.cs
+++ b/src/EFCore.Relational/Infrastructure/RelationalModelValidator.cs
@@ -2144,16 +2144,19 @@ protected virtual void ValidateMappingFragments(
entityType.DisplayName(), fragment.StoreObject.DisplayName()));
}
- var unmatchedLeafRowInternalFk = entityType.FindRowInternalForeignKeys(fragment.StoreObject)
- .FirstOrDefault(
- fk => entityType.FindRowInternalForeignKeys(mainStoreObject.Value)
- .All(mainFk => mainFk.PrincipalEntityType != fk.PrincipalEntityType));
- if (unmatchedLeafRowInternalFk != null)
+ foreach (var foreignKey in entityType.FindRowInternalForeignKeys(fragment.StoreObject))
{
- throw new InvalidOperationException(
- RelationalStrings.EntitySplittingUnmatchedMainTableSplitting(
- entityType.DisplayName(), fragment.StoreObject.DisplayName(),
- unmatchedLeafRowInternalFk.PrincipalEntityType.DisplayName()));
+ var principalMainFragment = StoreObjectIdentifier.Create(
+ foreignKey.PrincipalEntityType, fragment.StoreObject.StoreObjectType)!.Value;
+ if (principalMainFragment != mainStoreObject)
+ {
+ throw new InvalidOperationException(
+ RelationalStrings.EntitySplittingUnmatchedMainTableSplitting(
+ entityType.DisplayName(),
+ fragment.StoreObject.DisplayName(),
+ foreignKey.PrincipalEntityType.DisplayName(),
+ principalMainFragment.DisplayName()));
+ }
}
var propertiesFound = false;
diff --git a/src/EFCore.Relational/Properties/RelationalStrings.Designer.cs b/src/EFCore.Relational/Properties/RelationalStrings.Designer.cs
index 4a2a22d0240..85f252e0204 100644
--- a/src/EFCore.Relational/Properties/RelationalStrings.Designer.cs
+++ b/src/EFCore.Relational/Properties/RelationalStrings.Designer.cs
@@ -662,12 +662,12 @@ public static string EntitySplittingUnmappedMainFragment(object? entityType, obj
entityType, storeObject, storeObjectType);
///
- /// Entity type '{entityType}' has a split mapping for '{storeObject}' that shares the table with '{principalEntityType}', but the main mappings of these types do not share a table. Map the split fragments of '{entityType}' to non-shared tables or map the main fragment to a table that '{principalEntityType}' is also mapped to.
+ /// Entity type '{entityType}' has a split mapping for '{storeObject}' that is shared with the entity type '{principalEntityType}', but the main mappings of these types do not share a table. Map the split fragments of '{entityType}' to non-shared tables or map the main fragment to '{principalStoreObject}'.
///
- public static string EntitySplittingUnmatchedMainTableSplitting(object? entityType, object? storeObject, object? principalEntityType)
+ public static string EntitySplittingUnmatchedMainTableSplitting(object? entityType, object? storeObject, object? principalEntityType, object? principalStoreObject)
=> string.Format(
- GetString("EntitySplittingUnmatchedMainTableSplitting", nameof(entityType), nameof(storeObject), nameof(principalEntityType)),
- entityType, storeObject, principalEntityType);
+ GetString("EntitySplittingUnmatchedMainTableSplitting", nameof(entityType), nameof(storeObject), nameof(principalEntityType), nameof(principalStoreObject)),
+ entityType, storeObject, principalEntityType, principalStoreObject);
///
/// An error occurred while reading a database value for property '{entityType}.{property}'. See the inner exception for more information.
diff --git a/src/EFCore.Relational/Properties/RelationalStrings.resx b/src/EFCore.Relational/Properties/RelationalStrings.resx
index e883a10d1ef..fcac0a5f7f9 100644
--- a/src/EFCore.Relational/Properties/RelationalStrings.resx
+++ b/src/EFCore.Relational/Properties/RelationalStrings.resx
@@ -362,7 +362,7 @@
Entity type '{entityType}' has a split mapping for '{storeObject}', but it doesn't have a main mapping of the same type. Map '{entityType}' to '{storeObjectType}'.
- Entity type '{entityType}' has a split mapping for '{storeObject}' that shares the table with '{principalEntityType}', but the main mappings of these types do not share a table. Map the split fragments of '{entityType}' to non-shared tables or map the main fragment to a table that '{principalEntityType}' is also mapped to.
+ Entity type '{entityType}' has a split mapping for '{storeObject}' that is shared with the entity type '{principalEntityType}', but the main mappings of these types do not share a table. Map the split fragments of '{entityType}' to non-shared tables or map the main fragment to '{principalStoreObject}'.
An error occurred while reading a database value for property '{entityType}.{property}'. See the inner exception for more information.
diff --git a/test/EFCore.Relational.Tests/Infrastructure/RelationalModelValidatorTest.cs b/test/EFCore.Relational.Tests/Infrastructure/RelationalModelValidatorTest.cs
index 313e9c11ba5..47b3cdd560b 100644
--- a/test/EFCore.Relational.Tests/Infrastructure/RelationalModelValidatorTest.cs
+++ b/test/EFCore.Relational.Tests/Infrastructure/RelationalModelValidatorTest.cs
@@ -800,7 +800,45 @@ public void Detects_entity_splitting_with_partial_table_splitting()
});
VerifyError(
- RelationalStrings.EntitySplittingUnmatchedMainTableSplitting(nameof(OrderDetails), "Order", nameof(Order)),
+ RelationalStrings.EntitySplittingUnmatchedMainTableSplitting(nameof(OrderDetails), "Order", nameof(Order), "Order"),
+ modelBuilder);
+ }
+
+ [ConditionalFact]
+ public void Detects_entity_splitting_with_reverse_table_splitting()
+ {
+ var modelBuilder = CreateConventionModelBuilder();
+
+ modelBuilder.Entity(
+ cb =>
+ {
+ cb.Ignore(c => c.Customer);
+
+ cb.ToTable("Order");
+
+ cb.SplitToTable(
+ "OrderDetails", tb =>
+ {
+ tb.Property(c => c.PartitionId);
+ });
+
+ cb.OwnsOne(
+ c => c.OrderDetails, db =>
+ {
+ db.ToTable("OrderDetails");
+
+ db.Property("OtherAddress");
+ db.SplitToTable(
+ "Order", tb =>
+ {
+ tb.Property("OtherAddress");
+ });
+ });
+ cb.Navigation(c => c.OrderDetails).IsRequired();
+ });
+
+ VerifyError(
+ RelationalStrings.EntitySplittingUnmatchedMainTableSplitting(nameof(OrderDetails), "Order", nameof(Order), "Order"),
modelBuilder);
}