Skip to content

Commit

Permalink
[release/8.0] Avoid infinite recursion on identifying shadow FKs (#34891
Browse files Browse the repository at this point in the history
)

Fixes #34875
  • Loading branch information
AndriySvyryd authored Oct 14, 2024
1 parent 893bf3e commit e442d41
Show file tree
Hide file tree
Showing 2 changed files with 59 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 UseOldBehavior34875 =
AppContext.TryGetSwitch("Microsoft.EntityFrameworkCore.Issue34875", out var enabled34875) && enabled34875;

/// <summary>
/// Creates a new instance of <see cref="ForeignKeyPropertyDiscoveryConvention" />.
/// </summary>
Expand Down Expand Up @@ -142,7 +145,7 @@ private IConventionForeignKeyBuilder ProcessForeignKey(
&& fkProperty.ClrType.IsNullableType() == foreignKey.IsRequired
&& fkProperty.GetContainingForeignKeys().All(otherFk => otherFk.IsRequired == foreignKey.IsRequired))
{
var newType = fkProperty.ClrType.MakeNullable(!foreignKey.IsRequired);
var newType = fkProperty.ClrType.MakeNullable(!foreignKey.IsRequired && (!fkProperty.IsKey() || UseOldBehavior34875));
if (fkProperty.ClrType != newType)
{
fkProperty.DeclaringType.Builder.Property(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -737,6 +737,61 @@ protected override void OnModelCreating(ModelBuilder modelBuilder)
}
}

[ConditionalFact]
public virtual void ManyToManyWithPayloadAndNavsToJoinClassShadowFKsTest()
=> Model101Test();

protected class ManyToManyWithPayloadAndNavsToJoinClassShadowFKs
{
public class Post
{
public int Id { get; set; }
public List<Tag> Tag { get; } = [];
public List<PostTag> PostTags { get; } = [];
}

public class Tag
{
public int Id { get; set; }
public List<Post> Post { get; } = [];
public List<PostTag> PostTags { get; } = [];
}

public class PostTag
{
}

public class Context0 : Context101
{
public DbSet<Post> Post
=> Set<Post>();

public DbSet<Tag> Tag
=> Set<Tag>();

protected override void OnModelCreating(ModelBuilder modelBuilder)
=> modelBuilder.Entity<Post>()
.HasMany(e => e.Tag)
.WithMany(e => e.Post)
.UsingEntity<PostTag>(
l => l.HasOne<Tag>().WithMany(t => t.PostTags),
r => r.HasOne<Post>().WithMany(p => p.PostTags),
j => { });
}

public class Context1 : Context0
{
protected override void OnModelCreating(ModelBuilder modelBuilder)
=> modelBuilder.Entity<Post>()
.HasMany(e => e.Tag)
.WithMany(e => e.Post)
.UsingEntity<PostTag>(
l => l.HasOne<Tag>().WithMany(t => t.PostTags).HasForeignKey("TagId"),
r => r.HasOne<Post>().WithMany(p => p.PostTags).HasForeignKey("PostId"),
j => { });
}
}

[ConditionalFact]
public virtual void ManyToManyWithNoCascadeDeleteTest()
=> Model101Test();
Expand Down

0 comments on commit e442d41

Please sign in to comment.