0

I don't understand why the following code throws the following error:

System.Data.SqlClient.SqlException: „Introducing FOREIGN KEY constraint 'FK_dbo.CategoryUserRoles_dbo.AspNetUsers_GivenByUserId' on table 'CategoryUserRoles' may cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints.

The InverseProperty tag should fix this, but for some reason in this case it doesn't. Perhaps it's because it's used in the ApplicationUser which inherits from IdentityUser?

If I comment out the GivenByUser section, then everything works fine.

Here's the code:

public class ApplicationUser : IdentityUser
{
    //Relationships
    [InverseProperty("User")]
    public ICollection<CategoryUserRole> CategoryUserRoles { get; set; }
    [InverseProperty("GivenByUser")]
    public ICollection<CategoryUserRole> CategoryUserRolesIGave { get; set; }
}

public class Category
{
    [Key]
    [Required]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }

    [Required]
    [MaxLength(256)]
    [Index(IsUnique = true)]
    public string Name { get; set; }

    [Required]
    [MaxLength(1024)]
    public string Description { get; set; }

    [Required]
    public DateTime DateAdded { get; set; }

    //Relationships
    [InverseProperty("Category")]
    public ICollection<CategoryUserRole> CategoryUserRoles { get; set; }
}

public class CategoryUserRole
{
    [Key]
    [Required]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }

    [Required]
    public string Role { get; set; }

    [Required]
    public DateTime DateGiven { get; set; }

    //Relationships
    [Required]
    public string UserId { get; set; }
    [ForeignKey("UserId")]
    public ApplicationUser User { get; set; }

    [Required]
    public int CategoryId { get; set; }
    [ForeignKey("CategoryId")]
    public Category Category { get; set; }

    // ---- everything works fine after commenting out this section -----
    [Required]
    public string GivenByUserId { get; set; }
    [ForeignKey("GivenByUserId")]
    public ApplicationUser GivenByUser { get; set; }
}

// EDIT: This question has been marked as a duplicate of a 4-years-old question Introducing FOREIGN KEY constraint may cause cycles or multiple cascade paths - why? But back then the InverseProperty was not present. According to the InverseProperty section on this website https://learn.microsoft.com/en-us/ef/core/modeling/relationships it should be possible to define such relation without having to use Fluent. So my question remains unanswered.

ison
  • 173
  • 2
  • 9
  • This error cannot be resolved with data annotations (attributes). You have to use fluent configuration for that. – Ivan Stoev Aug 13 '17 at 13:29
  • I think that your statement is contradictory to what Microsoft says. Please look at https://learn.microsoft.com/en-us/ef/core/modeling/relationships at the InverseProperty section which does exactly what I want to achieve. The InverseProperty was introduced to solve this exact problem. Also note that in my example I don't have any cycles, so I think that it's not a duplicate. – ison Aug 13 '17 at 13:46
  • @IvanStoev You've marked this question as a duplicate of a 4-year-old question. But back then the InverseProperty was not present. Please reopen my question. Thanks. – ison Aug 13 '17 at 14:04
  • The `InverseProperty` and `ForeignKey` attributes can be used to resolve the relationship mappings. But there is no attribute for **cascade delete** behavior, which has to be turned off in order to resolve the exception you are getting. So old or not, the duplicate question answer still applies (you **have** to use fluent API `WillCascadeOnDelete(false)`) in all EF versions, including the latest EF Core. – Ivan Stoev Aug 13 '17 at 14:32
  • Thanks for your answer. So to clarify. You are saying that it's never possible to use cascade delete on tables which have 2 foreign keys to the same other table? Could you please provide a link to a documentation which could back your statement? If you are correct, then it's a major flaw in ms sql, because nothing bad can happen in this case. There are no cycles, and the order in which entities should be removed is clear. Disabling cascade delete is an overkill in this case. – ison Aug 13 '17 at 14:43
  • I can't find it now, but you can search SO / internet. I don't like that behavior either and fully agree with you, but it's inspired from Sql Server limitation (for instance, Oracle has absolutely no issues with multiple cascade paths). But of course EF is MS product, so they apply their db limitations. Also you are on SqlServer, so no options. You could try creating similar table structure and try setting up FK relationship with cascade delete directly in SqlServer and you'll see. – Ivan Stoev Aug 13 '17 at 15:02
  • 1
    Okay, I found more info and you were correct. Thanks for the answer. I simply made GivenByUserId nullable (by removing the Required attribute) and the error is gone. It's a hack, but I think it's the best solution in this case. – ison Aug 13 '17 at 15:03
  • You are welcome, glad to help cleaning it up :) Cheers. – Ivan Stoev Aug 13 '17 at 15:05

0 Answers0