.NET Core Entity Framework - 只添加新的子实体

.NET Core Entity Framework - Only add new child entities

我在更新具有数据库中已存在的子实体的父实体时遇到了一些问题。

我有一个与 Answer 实体存在多对多关系的 Question 实体。简化版本如下所示:

public class Question
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public Guid Id { get; set; }
    
    [JsonIgnore]
    public virtual List<QuestionParentRelation>? ParentQuestions { get; set; }
    [JsonIgnore]
    public virtual List<QuestionParentRelation>? ChildQuestions { get; set; }
    
    public string Name { get; set; }
    
    public virtual List<Answer>? PossibleAnswers { get; set; }
}

public class Answer
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public Guid Id { get; set; }
    
    public string AnswerText { get; set; }
    
    [JsonIgnore]
    public List<Question> Questions { get; set; }
}

但是与其他问题也存在多对多关系,因为在 UI 端有一个拖放功能,可以创建子后续问题等。 此关系包含 ParentQuestionAnswerId(一个外键,指示在显示子问题之前应该对父问题给出哪个答案)。

public class QuestionParentRelation
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public Guid RelationId { get; set; }

    public Guid? ParentId { get; set; }
    public Guid ChildId { get; set; }
    
    public virtual Question ParentQuestion { get; set; }
    public virtual Question ChildQuestion { get; set; }
    
    public int ParentHashNum { get; set; }
    public int ChildHashNum { get; set; }
    
    // FK: The answer that is needed before the child question is shown
    public Guid? ParentQuestionAnswerId { get; set; }
    [JsonIgnore]
    public virtual Answer? ParentQuestionAnswer { get; set; }

    public int Level { get; set; }
    public int Order { get; set; }
}

现在的问题是,每次我尝试更新问题实体(使用给定的现有答案实体列表)时:

  1. 我收到一条 错误消息,提示该条目存在重复项 具体答案 ID
  2. 如果我首先尝试从数据库中删除 Answer,我会收到一条错误消息,指出存在失败的外键约束 (ParentQuestionAnswerId)。 (但是如果首先删除 Answer 实体是唯一的解决方案我不希望所有 QuestionParentRelation 实体都将 ParentQuestionAnswerId 设置为 NULL,因为那样会也会影响不应编辑的关系)

这是我在 FluentAPI 中配置的:

builder.Entity<Question>()
    .HasMany(q => q.PossibleAnswers)
    .WithMany(a => a.Questions)
    .UsingEntity(join => join.ToTable("QuestionPossibleAnswers"));

builder.Entity<QuestionParentRelation>()
    .ToTable("QuestionParentRelations")
    .HasKey(r => new { r.RelationId });

builder.Entity<Question>()
    .HasMany(q => q.ParentQuestions)
    .WithOne(r => r.ChildQuestion)
    .HasForeignKey(r => r.ChildId);

builder.Entity<Question>()
    .HasMany(q => q.ChildQuestions)
    .WithOne(r => r.ParentQuestion)
    .HasForeignKey(r => r.ParentId);

好吧,对于任何偶然发现这个问题的人来说:我仍然不知道是否有一种方法可以让 EF 自行处理这个问题,但我通过循环问题的 DTO 中的答案解决了它对象,然后将它们与实体进行比较。

如果实体中已经存在答案,我只需将其从 DTO 中删除并将更新后的 DTO 发送到服务。这样,现有答案将不会被添加两次。

QuestionsController 的 HttpPut 方法内部

var question = _questionService.EagerGetBy(q => q.Id == Guid.Parse(id));
if (question is null)
    return NotFound("Geen resultaat gevonden voor Id " + id);

if (questionDto.PossibleAnswers != null && question.PossibleAnswers != null)
{
    questionDto.PossibleAnswers.ForEach(a =>
    {
        if (a.Id != null && question.PossibleAnswers.Contains(a))
            questionDto.PossibleAnswers.Remove(a);
    });
}