3

I'm trying to model a simple QA application using code first for learning purposes. Users should be able to ask questions, answer questions and write comments for both questions and answers. Here is my model classes:

[Table("UserProfile")]
public class UserProfile
{
    [Key]
    [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
    public int UserId { get; set; }

    public string UserName { get; set; }

    public DateTime? BirthDate { get; set; }

    public ICollection<Gym> Gyms { get; set; }
}

[Table("Question")]
public class Question
{
    [Key]
    [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
    public int QuestionId { get; set; }

    public int UserProfileId { get; set; }

    [ForeignKey("UserProfileId")]
    public UserProfile UserProfile { get; set; }

    public string Header { get; set; }

    public string Content { get; set; }

    [DatabaseGenerated(DatabaseGeneratedOption.Computed)]
    public DateTime CreateDate { get; set; }

    public ICollection<Answer> Answers { get; set; }

    public ICollection<QuestionComment> QuestionComments { get; set; }
}

[Table("QuestionComment")]
public class QuestionComment
{
    [Key]
    [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
    public int QuestionCommentId { get; set; }

    public int UserProfileId { get; set; }

    [ForeignKey("UserProfileId")]
    public UserProfile UserProfile { get; set; }

    public int QuestionId { get; set; }

    [ForeignKey("QuestionId")]
    public Question Question { get; set; }

    [Column("Content", TypeName = "ntext")]
    public string Content { get; set; }

    [DatabaseGenerated(DatabaseGeneratedOption.Computed)]
    public DateTime CreateDate { get; set; }
}

[Table("Answer")]
public class Answer
{
    [Key]
    [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
    public int AnswerId { get; set; }

    public int UserProfileId { get; set; }

    [ForeignKey("UserProfileId")]
    public UserProfile UserProfile { get; set; }

    public int QuestionId { get; set; }

    [ForeignKey("QuestionId")]
    public Question Question { get; set; }

    [Column("Content", TypeName="ntext")]
    public string Content { get; set; }

    [DatabaseGenerated(DatabaseGeneratedOption.Computed)]
    public DateTime CreateDate { get; set; }

    public IList<AnswerComment> AnswerComments { get; set; }
}

[Table("AnswerComment")]
public class AnswerComment
{
    [Key]
    [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
    public int AnswerCommentId { get; set; }

    public int UserProfileId { get; set; }

    [ForeignKey("UserProfileId")]
    public UserProfile UserProfile { get; set; }

    public int AnswerId { get; set; }

    [ForeignKey("AnswerId")]
    public Answer Answer { get; set; }

    [Column("Content", TypeName = "ntext")]
    public string Content { get; set; }

    [DatabaseGenerated(DatabaseGeneratedOption.Computed)]
    public DateTime CreateDate { get; set; }
}

And here is my db context class:

public class TestDbContext : DbContext
{
    public TestDbContext()
        : base("DefaultConnection")
    {
    }

    public DbSet<UserProfile> UserProfiles { get; set; }
    public DbSet<Question> Questions { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);

        // After update
        modelBuilder.Entity<UserProfile>()
            .HasMany(p => p.Questions)
            .WithRequired()
            .HasForeignKey(c => c.UserProfileId)
            .WillCascadeOnDelete(false);

        modelBuilder.Entity<UserProfile>()
            .HasMany(p => p.Answers)
            .WithRequired()
            .HasForeignKey(c => c.UserProfileId)
            .WillCascadeOnDelete(false);

        modelBuilder.Entity<UserProfile>()
            .HasMany(p => p.AnswerComments)
            .WithRequired()
            .HasForeignKey(c => c.UserProfileId)
            .WillCascadeOnDelete(false);

        modelBuilder.Entity<UserProfile>()
            .HasMany(p => p.QuestionComments)
            .WithRequired()
            .HasForeignKey(c => c.UserProfileId)
            .WillCascadeOnDelete(false);

        modelBuilder.Entity<Question>()
            .HasMany(p => p.Answers)
            .WithRequired()
            .HasForeignKey(c => c.QuestionId)
            .WillCascadeOnDelete(false);

        modelBuilder.Entity<Question>()
            .HasMany(p => p.QuestionComments)
            .WithRequired()
            .HasForeignKey(c => c.QuestionId)
            .WillCascadeOnDelete(false);

        modelBuilder.Entity<Answer>()
            .HasMany(p => p.AnswerComments)
            .WithRequired()
            .HasForeignKey(c => c.AnswerId)
            .WillCascadeOnDelete(false);
        // After update
    }
}

I'm getting the following error when creating db using the above declarations:

Introducing FOREIGN KEY constraint 'AnswerComment_UserProfile' on table 'AnswerComment' may cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints.\r\nCould not create constraint. See previous errors.

What do I have to do to fix this?

Thanks in advance,

2 Answers 2

2
+50

Try adding this to your UserProfile entity:

public virtual ICollection<AnswerComment> AnswerComments { get; set; }

And then add this to your modelBuilder, this should get rid off the error in your question, and you will probably have to do this for QuestionComment, Question, and Answer:

modelBuilder.Entity<AnswerComment>()
            .HasRequired(u => u.UserProfile)
            .WithMany(a => a.AnswerComments)
            .WillCascadeOnDelete(false);
Sign up to request clarification or add additional context in comments.

2 Comments

Are you sure of this? After adding these line I can't build the solution. I get: Cannot implicitly convert type 'System.Collections.Generic.ICollection<NS.Model.Question.AnswerComment>' to 'NS.Model.Question.AnswerComment'. An explicit conversion exists (are you missing a cast?)
@anilca seed my edit, try changing the WithOptional to a WithMany.
2

You have a table A that contains a FK to another table B. In the same time table A contains a FK to table C. Now, both tables B and C contains FKs to table D.

If all FKs are defined as delete cascade a record in table C can be deleted twice. This is not a logic problem, but SQL Server does not support this option.

To avoid this problem set on delete no action.

2 Comments

How can I set delete no action for this scenario?
in your FKs, try to add a cascadeDelete=false

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.