Aaron
Aaron

Reputation: 1061

Multiple cascading paths Error - Entity Framework Core

I am trying to setup a new database using Entity Framework Core but I am getting an error when calling the command "Update-Database" saying:

"Introducing FOREIGN KEY constraint 'FK_Answers_Users_UserId' on table 'Answers' may cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints."

I do not plan on actually deleting anything from the database but I would be fine with setting it delete everything related to user if a user is deleted.

Here are my models:

public class User
{
    public int Id { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string Email { get; set; }
    public string Username { get; set; }
    public string ImageUrl { get; set; }
    public DateTime DateCreated { get; set; }
    public DateTime DateModified { get; set; }
    public int AnswersFlagged { get; set; }
    public bool Status { get; set; }

    public IEnumerable<Dispute> Disputes { get; set; }
    public IEnumerable<Answer> Answers { get; set; }
}

public class Dispute
{
    public int Id { get; set; }
    public int UserId { get; set; }
    public int CategoryId { get; set; }
    public string Text { get; set; }
    public string OptionOneText { get; set; }
    public string OptionTwoText { get; set; }
    public string OptionThreeText { get; set; }
    public string OptionOneImageUrl { get; set; }
    public string OptionTwoImageUrl { get; set; }
    public string OptionThreeImageUrl { get; set; }
    public DateTime DateCreated { get; set; }
    public DateTime DateModified { get; set; }
    public bool Status { get; set; }

    public User User { get; set; }
    public Category Category { get; set; }
    public IEnumerable<Answer> Answers { get; set; }
}

public class Answer
{
    public int Id { get; set; }
    public int DisputeId { get; set; }
    public int UserId { get; set; }
    public int SelectedOption { get; set; }
    public string Comment { get; set; }
    public bool Flagged { get; set; }
    public DateTime DateCreated { get; set; }

    public Dispute Dispute { get; set; }
    public User User { get; set; }
}

public class Category
{
    public int Id { get; set; }
    public string Name { get; set; }
    public DateTime DateCreated { get; set; }
    public bool Status { get; set; }

    public IEnumerable<Dispute> Disputes { get; set; }
}

public class DisputeCategory
{
    public int Id { get; set; }
    public int DisputeId { get; set; }
    public int CategoryId { get; set; }

    public Dispute Dispute { get; set; }
    public Category Category { get; set; }
}

I have tried the follow with no luck in my DbContext:

1)

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Answer>()
        .HasOne(p => p.User)
        .WithMany(b => b.Answers)
        .OnDelete(DeleteBehavior.Restrict);
}

2)

 protected override void OnModelCreating(ModelBuilder modelBuilder)
 {
        modelBuilder.Entity<Answer>()
            .HasOne(p => p.User)
            .WithMany(b => b.Answers)
            .IsRequired(false);
 }

3)

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    foreach (var relationship in modelBuilder.Model.GetEntityTypes().SelectMany(e => e.GetForeignKeys()))
    {
        relationship.DeleteBehavior = DeleteBehavior.Restrict;
    }
}

What do I need to do to get this setup correctly?

Upvotes: 2

Views: 2863

Answers (1)

ocuenca
ocuenca

Reputation: 39326

I think this can be solve in you Answer entity, change DisputeId as nullable:

public class Answer
{
    public int Id { get; set; }
    public int? DisputeId { get; set; }
    //..

    public Dispute Dispute { get; set; }
    //..
}

And configure your relationships this way:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Answer>()
        .HasOne(p => p.User)
        .WithMany(b => b.Answers)
        .HasForeignKey(s =>s.UserId) ;

    modelBuilder.Entity<Answer>()
        .HasOne(p => p.Dispute)
        .WithMany(b => b.Answers)
        .HasForeignKey(s =>s.DisputeId) ;
}

The second relationship would be optional by convention, so that should solve your issue.

From EF core documentation:

By convention, cascade delete will be set to Cascade for required relationships and Restrict for optional relationships. Cascade means dependent entities are also deleted. Restrict means that dependent entities that are not loaded into memory will remain unchanged and must be manually deleted, or updated to point to a valid principal entity. For entities that are loaded into memory, EF will attempt to set the foreign key properties to null.

If you have a foreign key property in your entity class then the requiredness of the relationship is determined based on whether the foreign key property is required or optional

Upvotes: 4

Related Questions