3

我正在使用 Entity Framework 5 和 Code First。

我有两个用于测验应用程序的域实体问题答案。一个问题有几个可能的答案。一个问题也有一个正确的答案,它应该引用一个可能的答案。我在 to 实体之间的一对多和一对一关系的组合中遇到了一些问题。请参阅Q1Q2

这是实体的代码:

public class Question
{
    public virtual int Id { get; set; }
    [Required]
    public virtual string Text { get; set; }

    [InverseProperty("Question")] 
    public virtual ICollection<Answer> PossibleAnswers { get; set; }
    public virtual Answer CorrectAnswer { get; set; }        

    [DatabaseGenerated(DatabaseGeneratedOption.Computed)]
    public virtual DateTime? UpdateStamp { get; set; }
}

public class Answer
{
    public virtual int Id { get; set; }
    [Required]
    public virtual string Text { get; set; }

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

Q1:我应该怎么做才能在到数据库的一次往返中插入 Question 对象和引用的 Answers(通过属性 PossibleAnswers)(例如,一次调用上下文 SaveChanges)?当我在不先添加答案的情况下保存问题和答案时出现的错误是:

无法确定相关操作的有效排序。由于外键约束、模型要求或存储生成的值,可能存在依赖关系。

为了解决这个问题,我尝试了以下使用流利的 API 来获取要在问题之前添加的答案,只需调用 objectcontexts SaveChanges 即可:

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Question>()
            .HasOptional(q => q.CorrectAnswer)
            .WithRequired();

        base.OnModelCreating(modelBuilder);
    }

但是,这导致我出现另一个错误:

检测到有冲突的更改。当尝试插入具有相同键的多个实体时,可能会发生这种情况。

Q1 的流利 API 方法是否走在正确的道路上?为什么会出现错误信息?

Q2:删除问题时,我意识到会出现错误,因为无法在答案之前删除问题,反之亦然。我该如何解决这个问题?例如,是否应该在 Question.CorrectAnswer 和 Question.PossibleAnswers 上都指定 WillCascadeOnDelete?

4

1 回答 1

2

对于您的问题 Q1 和 Q2,您将需要两次往返/两次调用SaveChanges(除了可能使用存储过程解决问题)。

Q1:第一个呼叫Question.CorrectAnswer设置为null,第二个呼叫设置CorrectAnswer为存储的答案之一。

Q2:第一次呼叫设置Question.CorrectAnswernull和第二次呼叫删除Question和相关答案启用级联删除。

如果您不太担心两次往返,而是更担心与两次SaveChanges调用相对应的两次​​事务,则可以将包括两次调用在内的整个操作包装SaveChanges到一个手动事务中。(示例:EF:如何在事务中调用 SaveChanges 两次?

关于一对一关系:尽管从业务角度来看,关系CorrectAnswer是一对一的,但很难甚至不可能将其建模为与 EF 的一对一关系。

问题是 EF 不支持外键一对一关联,即外键(CorrectAnswerId 左右)具有唯一约束的关系。它仅支持共享主键一对一关联,其中从属( )的主键同时是主体( )Question的外键(for ) 。您的 Fluent 代码是此类共享主键关联的配置。但这意味着唯一有效的是与具有相同主键值的。虽然这在理论上是可以实现的(您的表的记录多于表),但很可能需要不使用自动生成的键,而是手动提供键。从一个改变Question.CorrectAnswerAnswerCorrectAnswerAnswerQuestionAnswerQuestionCorrectAnswersAnswer到另一个是不可能的。因此,我认为共享主键不适合您的模型。

更好的解决方案是删除您的 Fluent 映射。CorrectAnswer结果将是与表中可为空的外键的一对多关系Question。从数据库的角度来看,这意味着对于许多s 来说也是Answer如此,这在您的业务逻辑中可能是无稽之谈,因为每个问题都有自己独特的答案集,并且两个问题永远不会共享相同的答案。但是您可以通过不向. 尽管它不能完美地模拟业务约束,但它在技术上可以毫无问题地工作。CorrectAnswerQuestionQuestionsThisIsTheCorrectAnswerForAnswer

有关与 EF 建立一对一关系的困难的更多信息,请参阅以下博客文章:

于 2013-02-07T23:15:32.607 回答