'EF Core 5.0 Many-To-Many delete from nested collection

My models are like this (simplified):

    public class Request
    {
        public string Id { get; set; }
        public List<Tag> Tags { get; set; }
    }

    public class Tag
    {
        public string Id { get; set; }
        public List<Request> Requests { get; set; }
    }

DatabaseContext (as shown in documentation here: Many-To-Many):

    builder.Entity<Request>()
        .HasMany(r => r.Tags)
        .WithMany(f => f.Requests)
        .UsingEntity(j => j.ToTable("request_tags"));

How do I delete element from Request.Tags collection without deleteting tag itself? Basically I need to delete entry in join table. I tried in controller something like this:

    [HttpGet("[action]")]
    public async Task<IActionResult> DeleteTag(string requestId, string tagId)
    {
        var request = await _context.Requests
                    .Include(r => r.Tags)
                    .SingleOrDefaultAsync(r => r.Id.Equals(requestId));

        var itemToDelete = request.Tags.SingleOrDefault(f => f.Id.Equals(tagId));
             
        request.Tags.Remove(itemToDelete);
        _context.Requests.Update(request); //AsNoTracking behaviour is enabled
        await _context.SaveChangesAsync();

        return Ok();
    }

And it takes no effect. I can manually delete row on join table via _context.Database.ExecuteSqlRaw() but it seems like workaround. Is there a better way?



Solution 1:[1]

Here is how I think about it, I assume it is because EF requires you to be expressive by default, so you don't hurt yourself. Your code called Update(), which means you want to update a record, not do any deletes. It wants you to call Remove() on the record set itself.

As is change your Remove call to:

_context.Tags.Remove(itemToDelete);

Update: Just saw this here, it might be what you are looking for, read that link, I've never tried it though:

.OnDelete(DeleteBehavior.ClientCascade);

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1