Home > database >  How to delete child entities when updating a parent entity in EF 6?
How to delete child entities when updating a parent entity in EF 6?

Time:12-03

This is my entities:

public class Question
{
    public int Id { get; set; }
    public string Text { get; set; } = string.Empty;
    public ICollection<Answer> Answers { get; set; } = new List<Answer>();
    public TimeSpan TimeForAnswer { get; set; }
    public int TestId { get; set; }
}
public class Answer
{
    public int Id { get; set; }
    public string Text { get; set; } = string.Empty;
    public int QuestionId { get; set; }
    public int Points { get; set; }
}

If I update just my parent entity:

public void Update(Question entity)
{
    _dbContext.Questions.Update(entity);
}

EF will add/update child entities, but not delete if any missing. I searched, and found this post. And modified my method like this:

public void Update(Question entity)
{
    var existingParent = _db.Questions
        .Include(p => p.Answers)
        .SingleOrDefault(p => p.Id == entity.Id);
        
    if (existingParent != null)
    {
        existingParent.Answers.Clear();
    }

    _db.Questions.Update(entity);
}

And now I 'am getting this error:

System.InvalidOperationException: The instance of entity type 'Question' cannot be tracked because another instance with the same key value for {'Id'} is already being tracked. When attaching existing entities, ensure that only one entity instance with a given key value is attached. Consider using 'DbContextOptionsBuilder.EnableSensitiveDataLogging' to see the conflicting key values.

How to fix this?

CodePudding user response:

The call to:

_db.Questions.Update(entity);

tries to start tracking entity, but it's already being tracked by the query:

var existingParent = _db.Questions
    .Include(p => p.Answers)
    .SingleOrDefault(p => p.Id == entity.Id);

I'd go for:

public void Update(Question entity)
{
    var existingParent = _db.Questions
        .Include(p => p.Answers)
        .SingleOrDefault(p => p.Id == entity.Id);
        
    if (existingParent != null)
    {
        // Update Parent Entity Properties
        existingParent.Text = entity.Text;
        existingParent.TimeForAnswer = entity.TimeForAnswer;
        existingParent.TestId = entity.TestId;
        // remove existing from tracked Question
        existingParent.Answers.Clear();
        // add answers from Question in method param
        existingParent.Answers.AddRange(entity.Answers);
    }
    else
    {
        // Add the question with answers to the db
        _db.Questions.Add(entity);
    }
}
  • Related