流畅的API,一对一的关系和级联删除

时间:2018-01-11 19:07:08

标签: c# entity-framework

所以我有这个课程:

public class Question
{
    public int QuestionId { get; set; }
    public string QuestionText { get; set; }
    public bool IsInactive { get; set; }

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

而且:

public class Answer
{
    public Guid AnswerId { get; set; }
    public string AnswerText { get; set; }

    [Required]
    [ForeignKey(nameof(Question))]
    public int QuestionId { get; set; }
    [Required]
    public virtual Question Question { get; set; }
}

使用代码优先的实体框架,一切似乎都得到了设置,正如我所期望的那样。我在QuestionAnswer之间存在一对多关系,删除Question会导致关联的Answer消失(我认为)。

现在我想将其添加到Question类:

public virtual Answer RightAnswer { get; set; }

我想在QuestionAnswer之间建立一对一的关系(除了AnswersQuestion之间的一对多关系之外这是问题开始的地方。问题发生是因为级联删除。数据库现在看到它的方式,删除问题会删除答案(包括RightAnswer),这会导致它再次尝试删除Question(或者它可能会删除Answer 1}}删除Question,然后删除Answer,无论哪种方式)。要解决这个问题,我需要告诉它 not 级联删除该一对一关系。而且,不幸的是,要做到这一点,我必须深入研究流体API,在这里我不确定正确的方法。

我有这个:

modelBuilder.Entity<Question>()
    .HasRequired(p => p.RightAnswer)
    .WithRequiredDependent()
    .WillCascadeOnDelete(false);

但我真的不确定这应该是WithRequiredDependant还是WithRequiredPrinciple。或者在这种情况下甚至是重要的。

(是的,我知道另一个解决方案就是将IsRight bool添加到Answer,但现在我想弄清楚我是否可以这样做而不是这样做了)

2 个答案:

答案 0 :(得分:3)

尽管应尽可能避免关系数据库表之间的循环关系,但我可能会认真考虑“其他方法”。

按EF条款,关系的 principal 是被引用的表,依赖是引用主要PK到FK的表。

对于RightAnswer定义关系,Question将引用Answer到FK,因此Answer是主体,Question是依赖关系

从这个角度来看,您的流畅配置是正确的(Dependent中的WithRequiredDependent一词适用于正在配置的实体,在您的情况下Question - 来自Entity<Question>)。

然而,由于其他一对多关系的组合并非如此。为什么?因为循环依赖。 Answer需要QuestionId FK,因此如果没有先创建Question,就无法创建它。如果需要RightAnswer,则无需先创建Question即可创建Question。这会产生无法解决的鸡肉和鸡蛋问题。

因此RightQuestion应该可选。这导致了另一个问题。如果我们要求Answer,那么按惯例,EF会认为它是主体,这不是我们想要的。

因此,使用此类模型的唯一可行解决方案是使两端可选

modelBuilder.Entity<Question>()
    .HasOptional(p => p.RightAnswer)
    .WithOptionalDependent()
    .Map(m => m.MapKey("RightAnswerId"))
    .WillCascadeOnDelete(false);

请注意,最后两个流畅的API调用是可选的,可以跳过。 Map用于指定与本例RightAnswer_AnswerId中的常规名称不同的FK列名称。并且可以跳过WillCascadeOnDelete(false),因为按照惯例,可选关系会关闭级联删除。但是明确不会受到伤害,特别是在播放/修改模型时。

答案 1 :(得分:0)

One-to-zero/one Relationship

modelBuilder.Entity<Question>()
    .HasOptional(q => q.RightAnswer)
    .WithRequired(q => q.Question)
    .WillCascadeOnDelete(false);

One-to-one Relationship

modelBuilder.Entity<Question>()
    .HasRequired(q => q.RightAnswer)
    .WithRequiredPrincipal(q => q.Question)
    .WillCascadeOnDelete(false);