Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Entity Framework Core: How to solve Introducing FOREIGN KEY constraint may cause cycles or multiple cascade paths

I'm using Entity Framework Core with Code First approach but recieve following error when updating the database:

Introducing FOREIGN KEY constraint 'FK_AnEventUsers_Users_UserId' on table 'AnEventUsers' 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.

My entities are these:

public class AnEvent
{
    public int AnEventId { get; set; }
    public DateTime Time { get; set; }
    public Gender Gender { get; set; }
    public int Duration { get; set; }
    public Category Category { get; set; }
    public int MinParticipants { get; set; }
    public int MaxParticipants { get; set; }
    public string Description { get; set; }
    public Status EventStatus { get; set; }
    public int MinAge { get; set; }
    public int MaxAge { get; set; }
    public double Longitude { get; set; }
    public double Latitude { get; set; }

    public ICollection<AnEventUser> AnEventUsers { get; set; }

    public int UserId { get; set; }
    public User User { get; set; }
}


public class User
{
    public int UserId { get; set; }
    public int Age { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public Gender Gender { get; set; }
    public double Rating { get; set; }

    public ICollection<AnEventUser> AnEventUsers { get; set; }
}

public class AnEventUser
{
    public int AnEventId { get; set; }
    public AnEvent AnEvent { get; set; }

    public int UserId { get; set; }
    public User User { get; set; }

}

public class ApplicationDbContext:DbContext
{
    public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options):base(options)
    { }


    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<AnEventUser>()
            .HasOne(u => u.User).WithMany(u => u.AnEventUsers).IsRequired().OnDelete(DeleteBehavior.Restrict);


        modelBuilder.Entity<AnEventUser>()
            .HasKey(t => new { t.AnEventId, t.UserId });

        modelBuilder.Entity<AnEventUser>()
            .HasOne(pt => pt.AnEvent)
            .WithMany(p => p.AnEventUsers)
            .HasForeignKey(pt => pt.AnEventId);

        modelBuilder.Entity<AnEventUser>()
            .HasOne(eu => eu.User)
            .WithMany(e => e.AnEventUsers)
            .HasForeignKey(eu => eu.UserId);

    }

    public DbSet<AnEvent> Events { get; set; }
    public DbSet<User> Users { get; set; }
    public DbSet<AnEventUser> AnEventUsers { get; set; }
}

The issue I thought was that if we delete a User the reference to the AnEvent will be deleted and also the reference to AnEventUser will also be deleted, since there is a reference to AnEventUser from AnEvent as well we get cascading paths. But I remove the delete cascade from User to AnEventUser with:

 modelBuilder.Entity<AnEventUser>()
        .HasOne(u => u.User).WithMany(u => u.AnEventUsers).IsRequired().OnDelete(DeleteBehavior.Restrict);

But the error doesn't get resolved, does anyone see what is wrong? Thanks!

like image 240
Mu2tini Avatar asked Jan 19 '17 20:01

Mu2tini


People also ask

How do I get rid of migration EF core?

Delete your Migrations folder. Create a new migration and generate a SQL script for it. In your database, delete all rows from the migrations history table. Insert a single row into the migrations history, to record that the first migration has already been applied, since your tables are already there.

What is WillCascadeOnDelete?

WillCascadeOnDelete(Boolean) Configures whether or not cascade delete is on for the relationship.

What is fluent API used for?

Fluent API is an advanced way of specifying model configuration that covers everything that data annotations can do in addition to some more advanced configuration not possible with data annotations.

What is fluent API .NET core?

Entity Framework Fluent API is used to configure domain classes to override conventions. EF Fluent API is based on a Fluent API design pattern (a.k.a Fluent Interface) where the result is formulated by method chaining. In Entity Framework Core, the ModelBuilder class acts as a Fluent API.


3 Answers

In your sample code in OnModelCreating you have declared modelBuilder.Entity<AnEventUser>().HasOne(e => e.User)... twice: at start of method and at end.

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<AnEventUser>()       // THIS IS FIRST
        .HasOne(u => u.User).WithMany(u => u.AnEventUsers).IsRequired().OnDelete(DeleteBehavior.Restrict);


    modelBuilder.Entity<AnEventUser>()
        .HasKey(t => new { t.AnEventId, t.UserId });

    modelBuilder.Entity<AnEventUser>()
        .HasOne(pt => pt.AnEvent)
        .WithMany(p => p.AnEventUsers)
        .HasForeignKey(pt => pt.AnEventId);

    modelBuilder.Entity<AnEventUser>()       // THIS IS SECOND.
        .HasOne(eu => eu.User)               // THIS LINES
        .WithMany(e => e.AnEventUsers)       //   SHOULD BE
        .HasForeignKey(eu => eu.UserId);     //   REMOVED

}

Second call overrides first. Remove it.

like image 68
Dmitry Avatar answered Sep 21 '22 01:09

Dmitry


This is what I did from the answer of Dmitry,

and It worked for me.

Class:

public class EnviornmentControls
{
    public int Id { get; set; }
    ...

    public virtual Environment Environment { get; set; }
}

And it's Mapping

public EnviornmentControlsMap(EntityTypeBuilder<EnviornmentControls> entity)
{
        entity.HasKey(m => m.Id);           

        entity.HasOne(m => m.Environment)
            .WithMany(m => m.EnviornmentControls)
            .HasForeignKey(m => m.EnvironmentID)
            .OnDelete(DeleteBehavior.Restrict); // added OnDelete to avoid sercular reference 
}
like image 29
Bharat Avatar answered Sep 23 '22 01:09

Bharat


These solutions didn't work for my case, but I found a way. I am not quite sure yet if it is safe but there's just something that's happening with deleting. So I modified the generated Migration File instead of putting an override.

onDelete: ReferentialAction.Cascade

The reason I did this because all the overriding mentioned above is not working for me so I manually removed the code which relates to Cascading of Delete.

Just check which specific relation being mentioned at the error so you can go straightly.

Hope this will be able to help for some people who's having the same issue as mine.

like image 1
sshanzel Avatar answered Sep 23 '22 01:09

sshanzel