I have a following problem: when I try to update Question and provide a new keyword in Keywords property and the keyword isn't yet related with the question it is being properly added. Lets say there are two keywords mapped to the question. Then I send the update request with one keywords that is not related to the question yet. It results in Question being mapped to three keywords. When I send empty list of keywords, nothing changes. What I would like to happen is when I send one keyword - then it is just this one related to the question and rest is removed. How can I achieve the following ? Already I have tried adding "QuestionKeyword" segment inside Configure method for Keyword but it didn't change much. Also what happens is that keywords are being removed from the entity inside C# application, but when I add a dummy line of code with the same question being fetched from context again, then its question loads again after calling Include() - since they were never removed.
Consider the code below:
public class Keyword
{
public string Name { get; set; }
public List<Question> Questions { get; set; }
}
public class Question : AuditableEntity
{
public int Id { get; set; }
public string Content { get; set; }
public string Answer { get; set; }
public int Rating { get; set; }
public IList<Keyword> Keywords { get; set; } = new List<Keyword>();
}
This entities are configured in the following way:
public void Configure(EntityTypeBuilder<Keyword> builder)
{
builder.Ignore(entity => entity.DomainEvents);
builder.HasKey(entity => entity.Name);
builder.HasMany(entity => entity.Questions)
.WithMany(entity => entity.Keywords)
.UsingEntity<Dictionary<string, object>>(
"QuestionKeyword",
j => j.HasOne<Question>().WithMany().OnDelete(DeleteBehavior.Cascade),
j => j.HasOne<Keyword>().WithMany().OnDelete(DeleteBehavior.Cascade));
}
public void Configure(EntityTypeBuilder<Question> builder)
{
builder.HasKey(entity => entity.Id);
}
And this is handle method which updates the question. It was simplified so it just removes the question keywords for presentation purposes.
public async Task<Unit> Handle(UpdateQuestionCommand request, CancellationToken cancellationToken)
{
Question question = await _context.Questions.Include(q => q.Keywords).AsNoTracking().SingleOrDefaultAsync(q => q.Id == request.Id, cancellationToken);
if (question == null)
throw new NotFoundException($"Id = {request.Id}");
question.Keywords = null;
_context.Questions.Update(question);
question.DomainEvents.Add(new QuestionUpdatedEvent(question));
await _context.SaveChangesAsync(cancellationToken);
return Unit.Value;
}
CodePudding user response:
You must clear all keywords of the question then add new keywords into your question like this:
Question question = await _context.Questions.Include(q => q.Keywords).SingleOrDefaultAsync(q => q.Id == request.Id, cancellationToken);
question.Keywords.Clear();
....
But notice that AsNoTracking()
is removed!
Using AsNoTracking()
means that fetched objects changes dont matter for you and EF will ignore changes!