Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

EF Core 5 many-to-many specify on delete no action #22803

Closed
pantonis opened this issue Sep 28, 2020 · 7 comments
Closed

EF Core 5 many-to-many specify on delete no action #22803

pantonis opened this issue Sep 28, 2020 · 7 comments

Comments

@pantonis
Copy link

pantonis commented Sep 28, 2020

Ask a question

In EF Core 5 many to many relationship I have a case that I need to specify Delete no action. How can I do that without creating the join table my self?

Include provider and version information

EF Core version: 5.0 RC2 Daily builds
Database provider: Microsoft.EntityFrameworkCore.SqlServer
Target framework: .Net Core 3.1
Operating system: Win 10
IDE: Latest VS2019

@ajcvickers
Copy link
Member

@pantonis Can you give some details on why you would want to do this? For typical join tables. the two entities cannot be related if one of them does not exist.

@pantonis
Copy link
Author

Because I have self referencing m2m and causes cyclic references

@ajcvickers
Copy link
Member

@pantonis EF should build a model without cascading action by convention for self-referencing many-to-many relationships. Please attach a small, runnable project or post a small, runnable code listing that reproduces what you are seeing so that we can investigate.

@AndriySvyryd
Copy link
Member

EF Team Triage: This issue is lacking enough information for us to be able to effectively triage it. In particular, it is missing the following information requested in the new issue template. Can you please provide this information?

Steps to reproduce

Ideally include a complete code listing that we can run to reproduce the issue.

Alternatively, you can provide a project/solution that we can run.

BTW we're not just doing this to be mean 😄... we get a lot traffic on this project and it takes time to attempt to reproduce an issue based on fragments of information. In addition, our attempt is often unsuccessful as the exact conditions required to hit the issue are often not explicitly included in the code provided. To ensure we maximize the time we have to work on fixing bugs, implementing new features, etc. we ask that folks give us a self-contained way to reproduce an issue.

For a guide on submitting good bug reports, read Painless Bug Tracking.

BTW this is a canned response and may have info or details that do not directly apply to this particular issue. While we'd like to spend the time to uniquely address every incoming issue, we get a lot traffic on the EF projects and that is not practical. To ensure we maximize the time we have to work on fixing bugs, implementing new features, etc. we use canned responses for common triage decisions.

@pantonis
Copy link
Author

pantonis commented Oct 9, 2020

Sorry for late reply. I simplified the database and I can't reproduce it anymore.

@SebastianFalborg
Copy link

Hi. I have gotten the same "may cause cycles or multiple cascade paths" error, and has made a project to show it.
I am using ASP.NET Core 5 and EF Core 5
Here is the project on GitHub

My 3 models are

public class Team
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public Guid Id { get; set; }

    public string Name { get; set; }

    public ICollection<GymnastGroup> GymnastGroups { get; set; }

    public ICollection<FloorRoutine> FloorRoutines { get; set; }
}
public class GymnastGroup
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public Guid Id { get; set; }

    public Guid TeamId { get; set; }

    public string Name { get; set; }

    public Team Team { get; set; }

    public ICollection<FloorRoutine> FloorRoutines { get; set; }
}
public class FloorRoutine
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public Guid Id { get; set; }

    public Guid TeamId { get; set; }

    public string Name { get; set; }

    public Team Team { get; set; }

    public string SongName { get; set; }

    public ICollection<GymnastGroup> GymnastGroups { get; set; }
}

When I try to run "Update-Database" I get this error.

Introducing FOREIGN KEY constraint 'FK_FloorRoutineGymnastGroup_GymnastGroups_GymnastGroupsId' on table 'FloorRoutineGymnastGroup' may cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints.
Could not create constraint or index. See previous errors.

The migration shows that they are set to cascade on delete

migrationBuilder.CreateTable(
	name: "FloorRoutineGymnastGroup",
	columns: table => new
	{
		FloorRoutinesId = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
		GymnastGroupsId = table.Column<Guid>(type: "uniqueidentifier", nullable: false)
	},
	constraints: table =>
	{
		table.PrimaryKey("PK_FloorRoutineGymnastGroup", x => new { x.FloorRoutinesId, x.GymnastGroupsId });
		table.ForeignKey(
			name: "FK_FloorRoutineGymnastGroup_FloorRoutines_FloorRoutinesId",
			column: x => x.FloorRoutinesId,
			principalTable: "FloorRoutines",
			principalColumn: "Id",
			onDelete: ReferentialAction.Cascade);
		table.ForeignKey(
			name: "FK_FloorRoutineGymnastGroup_GymnastGroups_GymnastGroupsId",
			column: x => x.GymnastGroupsId,
			principalTable: "GymnastGroups",
			principalColumn: "Id",
			onDelete: ReferentialAction.Cascade);
	});

I could just remove the connection between the two classes I know, but I just want to know if it is intended to be like this.
Can I somehow tell the property that it should cascade on delete?

@AndriySvyryd
Copy link
Member

@isoap Since you have a relationship cycle in your model there's no good candidate for EF to make not cascade, so you'll have to choose one and configure it manually:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<FloorRoutine>()
        .HasMany(f => f.GymnastGroups)
        .WithMany(g => g.FloorRoutines)
        .UsingEntity<Dictionary<string, object>>(
            "GymnastGroupFloorRoutine",
            j => j.HasOne<GymnastGroup>().WithMany().OnDelete(DeleteBehavior.Cascade),
            j => j.HasOne<FloorRoutine>().WithMany().OnDelete(DeleteBehavior.ClientCascade));
}

We'll make this easier to do with #21535

@ajcvickers ajcvickers reopened this Oct 16, 2022
@ajcvickers ajcvickers closed this as not planned Won't fix, can't repro, duplicate, stale Oct 16, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants