Skip to content

Commit

Permalink
Avoid cascade cycles on SQL Server for derived-type referencing many-…
Browse files Browse the repository at this point in the history
…to-many

Fixes #28633
  • Loading branch information
ajcvickers committed Sep 1, 2022
1 parent cebba29 commit b7ee7ab
Show file tree
Hide file tree
Showing 12 changed files with 134 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ protected override DeleteBehavior GetTargetDeleteBehavior(IConventionForeignKey
}

var selfReferencingSkipNavigation = foreignKey.GetReferencingSkipNavigations()
.FirstOrDefault(s => s.Inverse != null && s.TargetEntityType == s.DeclaringEntityType);
.FirstOrDefault(s => s.Inverse != null && s.TargetEntityType.IsAssignableFrom(s.DeclaringEntityType));
if (selfReferencingSkipNavigation == null)
{
return deleteBehavior;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1557,7 +1557,7 @@ public static RuntimeForeignKey CreateForeignKey1(RuntimeEntityType declaringEnt
var runtimeForeignKey = declaringEntityType.AddForeignKey(new[] { declaringEntityType.FindProperty(""DerivedsId"")!, declaringEntityType.FindProperty(""DerivedsAlternateId"")! },
principalEntityType.FindKey(new[] { principalEntityType.FindProperty(""Id"")!, principalEntityType.FindProperty(""AlternateId"")! })!,
principalEntityType,
deleteBehavior: DeleteBehavior.Cascade,
deleteBehavior: DeleteBehavior.ClientCascade,
required: true);
return runtimeForeignKey;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,10 @@ protected override void OnModelCreating(ModelBuilder modelBuilder, DbContext con
.HasMany(e => e.TwoSkipShared)
.WithMany(e => e.OneSkipShared);

modelBuilder.Entity<EntityRoot>()
.HasMany(e => e.BranchSkipShared)
.WithMany(e => e.RootSkipShared);

// Nav:2 Payload:No Join:Concrete Extra:None
modelBuilder.Entity<EntityOne>()
.HasMany(e => e.TwoSkip)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,10 @@ protected override void OnModelCreating(ModelBuilder modelBuilder, DbContext con
.HasMany(e => e.TwoSkipShared)
.WithMany(e => e.OneSkipShared);

modelBuilder.Entity<EntityRoot>()
.HasMany(e => e.BranchSkipShared)
.WithMany(e => e.RootSkipShared);

// Nav:2 Payload:No Join:Concrete Extra:None
modelBuilder.Entity<EntityOne>()
.HasMany(e => e.TwoSkip)
Expand Down Expand Up @@ -439,6 +443,10 @@ protected override void OnModelCreating(ModelBuilder modelBuilder, DbContext con
.HasMany(e => e.TwoSkipShared)
.WithMany();

modelBuilder.Entity<UnidirectionalEntityBranch>()
.HasMany<UnidirectionalEntityRoot>()
.WithMany(e => e.BranchSkipShared);

// Nav:2 Payload:No Join:Concrete Extra:None
modelBuilder.Entity<UnidirectionalEntityOne>()
.HasMany(e => e.TwoSkip)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@ public class EntityBranch : EntityRoot
{
public long Number;
public ICollection<EntityOne> OneSkip;
public ICollection<EntityRoot> RootSkipShared;
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,5 @@ public class EntityRoot
public string Name;
public ICollection<EntityThree> ThreeSkipShared;
public ICollection<EntityCompositeKey> CompositeKeySkipShared;
public ICollection<EntityBranch> BranchSkipShared;
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ public ManyToManyData(ManyToManyContext context, bool useGeneratedKeys)
context.Set<Dictionary<string, object>>("EntityCompositeKeyEntityTwo").AddRange(CreateEntityCompositeKeyEntityTwos(context));
context.Set<Dictionary<string, object>>("EntityRootEntityThree").AddRange(CreateEntityRootEntityThrees(context));
context.Set<Dictionary<string, object>>("EntityCompositeKeyEntityRoot").AddRange(CreateEntityCompositeKeyEntityRoots(context));
context.Set<Dictionary<string, object>>("EntityBranchEntityRoot").AddRange(CreateEntityRootEntityBranches(context));
}

public IQueryable<TEntity> Set<TEntity>()
Expand Down Expand Up @@ -1163,6 +1164,39 @@ private static Dictionary<string, object> CreateEntityRootEntityThree(
e["RootSkipSharedId"] = context?.Entry(root).Property(e => e.Id).CurrentValue ?? root.Id;
});

private Dictionary<string, object>[] CreateEntityRootEntityBranches(ManyToManyContext context)
{
var branches = _roots.OfType<EntityBranch>().ToList();
return new[]
{
CreateEntityRootEntityBranch(context, branches[0], _roots[6]),
CreateEntityRootEntityBranch(context, branches[0], _roots[7]),
CreateEntityRootEntityBranch(context, branches[0], _roots[14]),
CreateEntityRootEntityBranch(context, branches[1], _roots[3]),
CreateEntityRootEntityBranch(context, branches[1], _roots[15]),
CreateEntityRootEntityBranch(context, branches[2], _roots[11]),
CreateEntityRootEntityBranch(context, branches[2], _roots[13]),
CreateEntityRootEntityBranch(context, branches[2], _roots[19]),
CreateEntityRootEntityBranch(context, branches[4], _roots[13]),
CreateEntityRootEntityBranch(context, branches[4], _roots[14]),
CreateEntityRootEntityBranch(context, branches[4], _roots[15]),
CreateEntityRootEntityBranch(context, branches[5], _roots[16]),
CreateEntityRootEntityBranch(context, branches[6], _roots[0]),
CreateEntityRootEntityBranch(context, branches[6], _roots[5]),
};
}

private static Dictionary<string, object> CreateEntityRootEntityBranch(
ManyToManyContext context,
EntityBranch branch,
EntityRoot root)
=> CreateInstance(
context?.Set<Dictionary<string, object>>("EntityRootEntityBranch"), (e, p) =>
{
e["BranchSkipSharedId"] = context?.Entry(branch).Property(e => e.Id).CurrentValue ?? branch.Id;
e["RootSkipSharedId"] = context?.Entry(root).Property(e => e.Id).CurrentValue ?? root.Id;
});

private Dictionary<string, object>[] CreateEntityCompositeKeyEntityRoots(ManyToManyContext context)
=> new[]
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@ public class EntityBranch : EntityRoot
{
public virtual long Number { get; set; }
public virtual ICollection<EntityOne> OneSkip { get; set; }
public virtual ICollection<EntityRoot> RootSkipShared { get; set; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,5 @@ public class EntityRoot
public virtual string Name { get; set; }
public virtual ICollection<EntityThree> ThreeSkipShared { get; set; }
public virtual ICollection<EntityCompositeKey> CompositeKeySkipShared { get; set; }
public virtual ICollection<EntityBranch> BranchSkipShared { get; set; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ public ManyToManyData(ManyToManyContext context, bool useGeneratedKeys)
context.Set<Dictionary<string, object>>("EntityCompositeKeyEntityTwo").AddRange(CreateJoinTwoToCompositeKeyShareds(context));
context.Set<Dictionary<string, object>>("EntityRootEntityThree").AddRange(CreateEntityRootEntityThrees(context));
context.Set<Dictionary<string, object>>("EntityCompositeKeyEntityRoot").AddRange(CreateJoinCompositeKeyToRootShareds(context));
context.Set<Dictionary<string, object>>("EntityBranchEntityRoot").AddRange(CreateEntityRootEntityBranches(context));

_unidirectionalOnes = CreateUnidirectionalOnes(context);
context.Set<UnidirectionalEntityOne>().AddRange(_unidirectionalOnes);
Expand Down Expand Up @@ -80,8 +81,8 @@ public ManyToManyData(ManyToManyContext context, bool useGeneratedKeys)
.AddRange(CreateUnidirectionalEntityRootEntityThrees(context));
context.Set<Dictionary<string, object>>("UnidirectionalEntityCompositeKeyUnidirectionalEntityRoot")
.AddRange(CreateUnidirectionalJoinCompositeKeyToRootShareds(context));

var entries = context.ChangeTracker.Entries<UnidirectionalEntityCompositeKey>().ToList();
context.Set<Dictionary<string, object>>("UnidirectionalEntityBranchUnidirectionalEntityRoot")
.AddRange(CreateUnidirectionalEntityRootUnidirectionalEntityBranches(context));
}

public IQueryable<TEntity> Set<TEntity>()
Expand Down Expand Up @@ -1186,6 +1187,40 @@ private static Dictionary<string, object> CreateEntityRootEntityThree(
e["RootSkipSharedId"] = context?.Entry(root).Property(e => e.Id).CurrentValue ?? root.Id;
});


private Dictionary<string, object>[] CreateEntityRootEntityBranches(ManyToManyContext context)
{
var branches = _roots.OfType<EntityBranch>().ToList();
return new[]
{
CreateEntityRootEntityBranch(context, branches[0], _roots[6]),
CreateEntityRootEntityBranch(context, branches[0], _roots[7]),
CreateEntityRootEntityBranch(context, branches[0], _roots[14]),
CreateEntityRootEntityBranch(context, branches[1], _roots[3]),
CreateEntityRootEntityBranch(context, branches[1], _roots[15]),
CreateEntityRootEntityBranch(context, branches[2], _roots[11]),
CreateEntityRootEntityBranch(context, branches[2], _roots[13]),
CreateEntityRootEntityBranch(context, branches[2], _roots[19]),
CreateEntityRootEntityBranch(context, branches[4], _roots[13]),
CreateEntityRootEntityBranch(context, branches[4], _roots[14]),
CreateEntityRootEntityBranch(context, branches[4], _roots[15]),
CreateEntityRootEntityBranch(context, branches[5], _roots[16]),
CreateEntityRootEntityBranch(context, branches[6], _roots[0]),
CreateEntityRootEntityBranch(context, branches[6], _roots[5]),
};
}

private static Dictionary<string, object> CreateEntityRootEntityBranch(
ManyToManyContext context,
EntityBranch branch,
EntityRoot root)
=> CreateInstance(
context?.Set<Dictionary<string, object>>("EntityBranchEntityRoot"), (e, p) =>
{
e["BranchSkipSharedId"] = context?.Entry(branch).Property(e => e.Id).CurrentValue ?? branch.Id;
e["RootSkipSharedId"] = context?.Entry(root).Property(e => e.Id).CurrentValue ?? root.Id;
});

private Dictionary<string, object>[] CreateJoinCompositeKeyToRootShareds(ManyToManyContext context)
=> new[]
{
Expand Down Expand Up @@ -2303,6 +2338,40 @@ private static Dictionary<string, object> CreateUnidirectionalEntityRootEntityTh
e["UnidirectionalEntityRootId"] = context?.Entry(root).Property(e => e.Id).CurrentValue ?? root.Id;
});


private Dictionary<string, object>[] CreateUnidirectionalEntityRootUnidirectionalEntityBranches(ManyToManyContext context)
{
var branches = _unidirectionalRoots.OfType<UnidirectionalEntityBranch>().ToList();
return new[]
{
CreateUnidirectionalEntityRootUnidirectionalEntityBranch(context, branches[0], _unidirectionalRoots[6]),
CreateUnidirectionalEntityRootUnidirectionalEntityBranch(context, branches[0], _unidirectionalRoots[7]),
CreateUnidirectionalEntityRootUnidirectionalEntityBranch(context, branches[0], _unidirectionalRoots[14]),
CreateUnidirectionalEntityRootUnidirectionalEntityBranch(context, branches[1], _unidirectionalRoots[3]),
CreateUnidirectionalEntityRootUnidirectionalEntityBranch(context, branches[1], _unidirectionalRoots[15]),
CreateUnidirectionalEntityRootUnidirectionalEntityBranch(context, branches[2], _unidirectionalRoots[11]),
CreateUnidirectionalEntityRootUnidirectionalEntityBranch(context, branches[2], _unidirectionalRoots[13]),
CreateUnidirectionalEntityRootUnidirectionalEntityBranch(context, branches[2], _unidirectionalRoots[19]),
CreateUnidirectionalEntityRootUnidirectionalEntityBranch(context, branches[4], _unidirectionalRoots[13]),
CreateUnidirectionalEntityRootUnidirectionalEntityBranch(context, branches[4], _unidirectionalRoots[14]),
CreateUnidirectionalEntityRootUnidirectionalEntityBranch(context, branches[4], _unidirectionalRoots[15]),
CreateUnidirectionalEntityRootUnidirectionalEntityBranch(context, branches[5], _unidirectionalRoots[16]),
CreateUnidirectionalEntityRootUnidirectionalEntityBranch(context, branches[6], _unidirectionalRoots[0]),
CreateUnidirectionalEntityRootUnidirectionalEntityBranch(context, branches[6], _unidirectionalRoots[5]),
};
}

private static Dictionary<string, object> CreateUnidirectionalEntityRootUnidirectionalEntityBranch(
ManyToManyContext context,
UnidirectionalEntityBranch branch,
UnidirectionalEntityRoot root)
=> CreateInstance(
context?.Set<Dictionary<string, object>>("UnidirectionalEntityBranchUnidirectionalEntityRoot"), (e, p) =>
{
e["BranchSkipSharedId"] = context?.Entry(branch).Property(e => e.Id).CurrentValue ?? branch.Id;
e["UnidirectionalEntityRootId"] = context?.Entry(root).Property(e => e.Id).CurrentValue ?? root.Id;
});

private Dictionary<string, object>[] CreateUnidirectionalJoinCompositeKeyToRootShareds(ManyToManyContext context)
=> new[]
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,5 @@ public class UnidirectionalEntityRoot
public virtual int Id { get; set; }
public virtual string Name { get; set; }
public virtual ICollection<UnidirectionalEntityThree> ThreeSkipShared { get; set; }
public virtual ICollection<UnidirectionalEntityBranch> BranchSkipShared { get; set; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,11 @@ protected override void OnModelCreating(ModelBuilder modelBuilder, DbContext con
.WithMany(e => e.OneSkipShared)
.UsingEntity(t => t.ToTable(tb => tb.IsTemporal()));

modelBuilder.Entity<EntityRoot>()
.HasMany(e => e.BranchSkipShared)
.WithMany(e => e.RootSkipShared)
.UsingEntity(t => t.ToTable(tb => tb.IsTemporal()));

// Nav:2 Payload:No Join:Concrete Extra:None
modelBuilder.Entity<EntityOne>()
.HasMany(e => e.TwoSkip)
Expand Down Expand Up @@ -203,6 +208,11 @@ protected override void OnModelCreating(ModelBuilder modelBuilder, DbContext con
.WithMany()
.UsingEntity(t => t.ToTable(tb => tb.IsTemporal()));

modelBuilder.Entity<UnidirectionalEntityBranch>()
.HasMany<UnidirectionalEntityRoot>()
.WithMany(e => e.BranchSkipShared)
.UsingEntity(t => t.ToTable(tb => tb.IsTemporal()));

// Nav:2 Payload:No Join:Concrete Extra:None
modelBuilder.Entity<UnidirectionalEntityOne>()
.HasMany(e => e.TwoSkip)
Expand Down

0 comments on commit b7ee7ab

Please sign in to comment.