Skip to content

Commit

Permalink
Avoid infinite loop during foreign key discovery
Browse files Browse the repository at this point in the history
Fixes #29826
  • Loading branch information
AndriySvyryd committed Dec 14, 2022
1 parent bf20e32 commit fe18cd6
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@ public class ForeignKeyPropertyDiscoveryConvention :
IPropertyFieldChangedConvention,
IModelFinalizingConvention
{
private static readonly bool QuirkEnabled29826
= AppContext.TryGetSwitch("Microsoft.EntityFrameworkCore.Issue29826", out var enabled) && enabled;

/// <summary>
/// Creates a new instance of <see cref="ForeignKeyPropertyDiscoveryConvention" />.
/// </summary>
Expand Down Expand Up @@ -309,7 +312,8 @@ private IConventionForeignKeyBuilder ProcessForeignKey(
: relationshipBuilder;
}

if (conflictingFKCount == 0)
if ((!QuirkEnabled29826 && conflictingFKCount >= 0)
|| (QuirkEnabled29826 && conflictingFKCount == 0))
{
return ((ForeignKey)foreignKey).Builder.ReuniquifyImplicitProperties(false);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -811,6 +811,44 @@ public void Does_not_match_if_a_foreign_key_on_the_best_candidate_property_alrea
Assert.Throws<InvalidOperationException>(() => ValidateModel()).Message);
}

[ConditionalFact]
public void Does_not_match_if_a_foreign_key_on_the_best_candidate_property_already_configured_explicitly()
{
var dependentTypeBuilder = DependentType.Builder;
var fkProperty = dependentTypeBuilder.Property(DependentEntity.SomeNavPeEKaYProperty, ConfigurationSource.Convention).Metadata;
dependentTypeBuilder.Property(DependentEntity.PrincipalEntityIDProperty, ConfigurationSource.Convention);
dependentTypeBuilder.Property(DependentEntity.PrincipalEntityPeEKaYProperty, ConfigurationSource.Convention);
dependentTypeBuilder.Property(DependentEntity.PeEKaYProperty, ConfigurationSource.Convention);

var derivedTypeBuilder = _model.Entity(typeof(DerivedPrincipalEntity), ConfigurationSource.Convention);
derivedTypeBuilder.HasBaseType(PrincipalType, ConfigurationSource.Convention);

var relationshipBuilder = dependentTypeBuilder
.HasRelationship(derivedTypeBuilder.Metadata, new[] { fkProperty }, ConfigurationSource.Explicit);
var compositeRelationshipBuilder = dependentTypeBuilder
.HasRelationship(PrincipalTypeWithCompositeKey, new[] { fkProperty }, ConfigurationSource.Explicit);

var newRelationshipBuilder = dependentTypeBuilder.HasRelationship(
PrincipalType, "SomeNav", null, ConfigurationSource.Convention);

Assert.Equal(
"SomeNav" + nameof(PrincipalEntity.PeeKay),
newRelationshipBuilder.Metadata.Properties.Single().Name);

newRelationshipBuilder = RunConvention(newRelationshipBuilder);

var fk = (IReadOnlyForeignKey)relationshipBuilder.Metadata;
Assert.Same(fkProperty, fk.Properties.Single());
Assert.False(fk.IsUnique);

var newFk = newRelationshipBuilder.Metadata;
Assert.Equal(3, DependentType.GetForeignKeys().Count());
Assert.Equal("SomeNav" + nameof(PrincipalEntity.PeeKay), newFk.Properties.Single().Name);
Assert.Null(newFk.GetPropertiesConfigurationSource());

ValidateModel();
}

[ConditionalFact]
public void Logs_warning_if_foreign_key_property_names_are_order_dependent()
{
Expand Down

0 comments on commit fe18cd6

Please sign in to comment.