如何首先解决EF 5代码中的一对一和一对多组合关系
本文关键字:一对一 一对多 组合 关系 解决 何首先 EF 代码 | 更新日期: 2023-09-27 17:58:04
我正在使用实体框架 5 和代码优先。
我有两个用于测验应用程序的域实体问题和答案。一个问题有几个可能的答案。一个问题也有一个正确答案,应该引用一个可能的答案。我在实体之间的一对多和一对一关系的组合中遇到了一些问题。参见问题 1 和问题 2。
这是实体的代码:
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:我应该怎么做才能在一次往返数据库(例如,对上下文 SaveChanges 的一次调用(中插入问题对象和引用的答案(通过属性 PossibleAnswers(?当我保存问题和答案而不先添加答案时,我得到的错误是:
无法确定从属操作的有效顺序。由于外键约束、模型要求或存储生成的值,可能存在依赖项。
为了解决这个问题,我尝试了以下内容,使用流畅的 API 在只需调用对象上下文 SaveChanges 即可完成所有操作时,在问题之前添加答案:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Question>()
.HasOptional(q => q.CorrectAnswer)
.WithRequired();
base.OnModelCreating(modelBuilder);
}
但是,这导致我遇到另一个错误:
检测到冲突的更改。尝试插入具有相同键的多个实体时,可能会发生这种情况。
我在第一季度使用流畅的 API 方法是否走在正确的道路上?为什么出现错误消息?
Q2:删除问题时,我意识到会出现错误,因为无法在答案之前删除问题,反之亦然。我该如何解决这个问题?例如,WillCascadeOnDelete 是否应该同时在 Question.CorrectAnswer 和 Question.PossibleAnswers 上指定?
对于您的问题 Q1 和 Q2,您将需要两次往返/两次调用SaveChanges
(除了解决存储过程的问题(。
问题 1:第一个呼叫Question.CorrectAnswer
设置为 null
第二个呼叫,将CorrectAnswer
设置为存储的答案之一。
Q2:第一个呼叫设置Question.CorrectAnswer
null
,第二个呼叫删除Question
和相关答案,并启用级联删除。
如果您不太担心两次往返,而是更担心对应于两个SaveChanges
调用的两个事务,则可以将包括两个SaveChanges
调用在内的整个操作包装到一个手动事务中。(示例:EF:如何在事务中调用 SaveChanges 两次?
关于一对一关系:尽管从业务角度来看,CorrectAnswer
的关系是一对一的,但很难甚至不可能将其建模为与 EF 的一对一关系。
问题是 EF 不支持外键一对一关联,即外键(CorrectAnswerId 左右(具有唯一约束的关系。它只支持共享主键一对一关联,其中依赖(Question
(的主键是同时与主键(Answer
(的外键(用于Question.CorrectAnswer
(。您的 Fluent 代码是此类共享主键关联的配置。但这意味着唯一有效的CorrectAnswer
是与Question
具有相同主键值的Answer
。虽然这在理论上是可以实现的(您的Answer
表比Question
表有更多的记录(,但它很可能不需要使用自动生成的键,而是手动提供键。将CorrectAnswers
从一个Answer
更改为另一个是不可能的。因此,在我看来,共享主键不适合您的模型。
更好的解决方案是删除您的 Fluent 映射。结果将是与Question
表中CorrectAnswer
的可为空外键的一对多关系。从数据库的角度来看,这意味着相同的Answer
可能是许多Question
的CorrectAnswer
,这在您的业务逻辑中可能是无稽之谈,因为每个问题都有自己独特的答案集,并且两个问题永远不会共享相同的答案。但是,您可以通过不向Answer
添加反向集合属性(如 QuestionsThisIsTheCorrectAnswerFor
(来从业务逻辑中"隐藏"这种一对多关系。尽管它不能完美地对业务约束进行建模,但它在技术上可以毫无问题地工作。
有关与 EF 一对一关系的困难的更多信息,请参阅以下博客文章:
- 共享主键一对一关联
- 一对一外键关联