实体框架6与映射外键有关的问题

时间:2018-07-24 14:31:09

标签: c# entity-framework

我有3个实体:问题

public enum QuestionType
{
    Scenario,
    Step
}

public class Question
{
    public int Id { get; set; }
    public int CategoryId { get; set; }
    [Required] [MaxLength(255)] public string Text { get; set; }
    [MaxLength(255)] public string FrameText { get; set; }
    public int Order { get; set; }
    public QuestionType Type { get; set; }

    public DefaultAnswer DefaultAnswer { get; set; }
    public IList<Answer> Answers { get; set; }
}

答案

public class Answer
{
    public int Id { get; set; }
    public int QuestionId { get; set; }
    [Required] [MaxLength(255)] public string Text { get; set; }
    public int Order { get; set; }

    public Scenario Scenario { get; set; }
    public IList<Formula> Formulas { get; set; }
    public IList<Image> Images { get; set; }
}

最后, DefaultAnswer

public class DefaultAnswer
{
    public int QuestionId { get; set; }
    public int AnswerId { get; set; }

    public Answer Answer { get; set; }
    public Question Question { get; set; }
}

问题答案之间的关系是显而易见的。我想为问题设置 DefaultAnswer ,所以我已将导航属性DefaultAnswer添加到 Question 模型中。 这是可选的,因为它可以为空。

所以,我试图建立这样的关系:

modelBuilder.Entity<DefaultAnswer>().HasKey(m => new { m.QuestionId, m.AnswerId });
modelBuilder.Entity<Question>().HasOptional(m => m.DefaultAnswer).WithRequired(m => m.Question);
modelBuilder.Entity<DefaultAnswer>().HasRequired(m => m.Answer).WithMany().HasForeignKey(m => m.AnswerId);

但这不起作用,它在 DefaultAnswers 表中创建了另一个名为Question_Id的字段。 这是EF生成的:

public override void Up()
{
    CreateTable(
        "dbo.DefaultAnswers",
        c => new
            {
                QuestionId = c.Int(nullable: false),
                AnswerId = c.Int(nullable: false),
                Question_Id = c.Int(nullable: false),
            })
        .PrimaryKey(t => new { t.QuestionId, t.AnswerId })
        .ForeignKey("dbo.Answers", t => t.AnswerId, cascadeDelete: true)
        .ForeignKey("dbo.Questions", t => t.Question_Id)
        .Index(t => t.AnswerId)
        .Index(t => t.Question_Id);

}

这不是我想要的。 我实际上想要这个:

public override void Up()
{
    CreateTable(
        "dbo.DefaultAnswers",
        c => new
            {
                QuestionId = c.Int(nullable: false),
                AnswerId = c.Int(nullable: false),
            })
        .PrimaryKey(t => new { t.QuestionId, t.AnswerId })
        .ForeignKey("dbo.Answers", t => t.AnswerId, cascadeDelete: true)
        .ForeignKey("dbo.Questions", t => t.QuestionId)
        .Index(t => t.AnswerId)
        .Index(t => t.QuestionId);

}

有人知道我如何创建这种关系,同时又将导航属性保留在问题中吗?

2 个答案:

答案 0 :(得分:0)

首先,建议仅将答案标记为“默认”的评论听起来不错,但试图帮助解决实际问题。...

确定,我认为所做的编辑会为您提供所需的内容。...

所以,我在这里使用的模型:

public enum QuestionType
{
    Scenario,
    Step
}

public class Question
{
    public int Id { get; set; }
    public int CategoryId { get; set; }
    [Required] [MaxLength(255)]
    public string Text { get; set; }
    [MaxLength(255)]
    public string FrameText { get; set; }
    public int Order { get; set; }
    public QuestionType Type { get; set; }

    public DefaultAnswer DefaultAnswer { get; set; }
    public IList<Answer> Answers { get; set; }
}
public class Answer
{
    public int Id { get; set; }
    public int QuestionId { get; set; }
    [Required]
    [MaxLength(255)]
    public string Text { get; set; }
    public int Order { get; set; }

    public Scenario Scenario { get; set; }
    public Question Question { get; set; }

    //commented these out for the sake of this
    //example
   /*public IList<Formula> Formulas { get; set; }
    public IList<Image> Images { get; set; }*/
}

public class DefaultAnswer
{
    public int QuestionId { get; set; }
    public int AnswerId { get; set; }

    public Answer Answer { get; set; }
    public Question Question { get; set; }
}

因此定义的关系:

//don't need a compound key for answers... 
//easier to just let each answer be entirely unique.            
modelBuilder.Entity<Answer>().HasKey(m => m.Id );

modelBuilder.Entity<Answer>().HasRequired(m => m.Question)
    .WithMany(q => q.Answers).HasForeignKey(m => m.QuestionId);

modelBuilder.Entity<Question>()
    .HasOptional(m => m.DefaultAnswer)
    .WithOptionalDependent(m => m.Question);

//default answer is basically a mapping table between questions and answers.
//so it has a compound key.  In fact the table should consist of ONLY these two key
//fields...
modelBuilder.Entity<DefaultAnswer>()
    .HasKey(m => new { m.AnswerId, m.QuestionId });              

这对我来说是这样的:

CreateTable(
            "dbo.DefaultAnswers",
            c => new
                {
                    AnswerId = c.Int(nullable: false),
                    QuestionId = c.Int(nullable: false),
                })
            .PrimaryKey(t => new { t.AnswerId, t.QuestionId })
            .ForeignKey("dbo.Answers", t => t.AnswerId, cascadeDelete: true)
            .Index(t => t.AnswerId);

我唯一不了解的是如何设置级联删除行为...有点担心删除'DefaultAnswer'记录会删除答案-为时已晚,我的大脑无法正常工作恐怕这个!

答案 1 :(得分:0)

我不确定引入DefaultAnswer实体的目的是什么。但是没有这种关系就可以建模。 EG:

public enum QuestionType
{
    Scenario,
    Step
}

public class Question
{
    public int Id { get; set; }
    public int CategoryId { get; set; }
    [Required] [MaxLength(255)] public string Text { get; set; }
    [MaxLength(255)] public string FrameText { get; set; }
    public int Order { get; set; }
    public QuestionType Type { get; set; }

    public int? DefaultAnswerId { get; set; }

    [ForeignKey("Id,DefaultAnswerId")]
    public Answer DefaultAnswer { get; set; }
    public IList<Answer> Answers { get; set; }
}
public class Answer
{
    public int Id { get; set; }
    public int QuestionId { get; set; }
    [Required] [MaxLength(255)] public string Text { get; set; }
    public int Order { get; set; }

    public virtual Question Question { get; set; }

    //public Scenario Scenario { get; set; }
    //public IList<Formula> Formulas { get; set; }
    //public IList<Image> Images { get; set; }
}
class Db: DbContext
{
    public DbSet<Question> Question { get; set; }
    public DbSet<Answer> Answer { get; set; }



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

        modelBuilder.Entity<Answer>().HasKey(m => new { m.QuestionId, m.Id });
        modelBuilder.Entity<Answer>().HasRequired(m => m.Question).WithMany(q => q.Answers).HasForeignKey( m => m.QuestionId);
        modelBuilder.Entity<Question>().HasOptional(m => m.DefaultAnswer);


    }


}