'EF Core - generic way to merge child records based on current db state and equality

I have a scenario where during an Update request of a parent entity, I have a collection of children entities in my dto, and want to merge them in the DB so that it either:

  1. Replaces it if something changed.
  2. Adds it if it doesn't already exist.
  3. Deletes it if it doesn't exist in the dto.

Front-end: my page allows you to edit the name of the book and add/edit/delete genres associated with the book. I have a data grid to manage the genres collection of a book and the ids are created on the client using guids, they'll always be unique across all scenarios.

An example of the js object that is sent up to a controller is like:

const bookState = {
        id: "xx-xx-xx",
        title: "Title X",
        genres: [{
                id: "xx-xx-xx",
                name: "sci-fi"
            },
            {
                id: "xxx-xx",
                name: "autobiography}, 
            ]
        }

Entities:

public class Book
{
   public Guid Id { get; set; }
   public string Title { get; set; }
   public List<Genre> genres { get; set; } = new();
}

public class Genre
{
   public Guid Id { get; set; }
   public string Name {get; set;} 
}

Here's the Update method where I would like to handle this entity and its children:

public async Task UpdateBook (Request request, CancellationToken cancellationToken)
{
     Book? entity = await _context.Books
         .Include(b => b.Genres)
         .FirstOrDefaultAsync(b => b.Id == request.Id, cancellationToken);

     if (entity == null)
     {
        // return book not found
     }

     entity.Title = request.Book.Title;

     // remove genres in db that are not in the request (ie, they were deleted from user)
     entity.Genres.RemoveAll(x => !request.Book.Genres.Select(r => r.Id).Contains(x.Id));

     //new ones to add
     var newGenres = request.Book.Genres.Where(x => !entity.Genres.Select(r => r.Id).Contains(x.Id));
     foreach (var item in newGenres)
     {
         _context.Genres.Add(new Genre(item.Id, item.Name, request.Id));
     }

     // LINQ to get the list of existing genres on this entity so I 
     // could iterate through them and update the individual fields for each one in 
     // the request that matches?
 
     _context.Update(entity)
     _context.SaveChangesAsync(cancellationToken);
}

What would the linq query be to update the existing genres ?

I'm using EF Core 6 code-first. First time with this, it just seems like it would be easier-but maybe this is an unusual use case.

Thanks



Sources

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

Source: Stack Overflow

Solution Source