Skip to content

Commit

Permalink
Validate that if any fragments use table sharing then the main fragme…
Browse files Browse the repository at this point in the history
…nts are mapped to the same table

Fixes #29104
  • Loading branch information
AndriySvyryd committed Oct 6, 2022
1 parent c830def commit 4a24149
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 15 deletions.
21 changes: 12 additions & 9 deletions src/EFCore.Relational/Infrastructure/RelationalModelValidator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion src/EFCore.Relational/Properties/RelationalStrings.resx
Original file line number Diff line number Diff line change
Expand Up @@ -362,7 +362,7 @@
<value>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}'.</value>
</data>
<data name="EntitySplittingUnmatchedMainTableSplitting" xml:space="preserve">
<value>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.</value>
<value>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}'.</value>
</data>
<data name="ErrorMaterializingProperty" xml:space="preserve">
<value>An error occurred while reading a database value for property '{entityType}.{property}'. See the inner exception for more information.</value>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<Order>(
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<string>("OtherAddress");
db.SplitToTable(
"Order", tb =>
{
tb.Property("OtherAddress");
});
});
cb.Navigation(c => c.OrderDetails).IsRequired();
});

VerifyError(
RelationalStrings.EntitySplittingUnmatchedMainTableSplitting(nameof(OrderDetails), "Order", nameof(Order), "Order"),
modelBuilder);
}

Expand Down

0 comments on commit 4a24149

Please sign in to comment.