'How to override List property in EF Core 6?

I have a problem, in database I have an object of class Catalog with 3 elements in CatalogUsers. I want to replace that list with 2 element list being the orginal one without 1 position. My aim is to delete element that miss in new list.

CatalogUsers is many to many relation beetwen Catalog and User

public class Catalog
{
    [Key, Column(Order = 1)]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }
    public string Name { get; set; }

    public string DefaultCurrencyCode { get; set; }
    public virtual Currency? DefaultCurrency { get; set; }

    public virtual List<CatalogUser>? CatalogUsers { get; set; }
}

public class CatalogUser
{
    public int CatalogId { get; set; }
    public virtual Catalog? Catalog { get; set; }

    public int UserId { get; set; }
    public virtual User? User { get; set; }

    public CatalogUserRole Role { get; set; }
}
public class User
{
    [Key, Column(Order = 1)]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }
    public string? Username { get; set; }
    public string? Email { get; set; }
    public string? Password { get; set; }

    public virtual List<CatalogUser>? CatalogUsers { get; set; }
}

For now i tried to do it this way:

public async Task<int> UpdateAsync(Catalog model)
{
    var _catalog = await GetByIdAsync(model.Id);
    if (_catalog is null) return 0;
    _catalog.Name = model.Name;
    _catalog.DefaultCurrencyCode = model.DefaultCurrencyCode;
    _catalog.CatalogUsers = model.CatalogUsers;
    _context.Catalogs.Update(_catalog);
    return await _context.SaveChangesAsync();
}

But it does not work the missing element is still in DB



Solution 1:[1]

This can be done using Cascaded Delete, as described in the docs.

But for cascading to happen, the tracked entities need to be modified. If you replace the list with a new list excluding the removed items, the tracking is severed. EF will try to match elements in the list to entities (or even add duplicates of entities in the database), but removed items will not be marked for deletion.

You need to manually remove the items from the tracked entity. E.g.

public async Task<int> UpdateAsync(Catalog model)
{
    var _catalog = await GetByIdAsync(model.Id);
    if (_catalog is null) return 0;
    _catalog.Name = model.Name;

    foreach(var catalogUser in _catalog.CatalogUsers.
        .Where(cuIdDb => !model.CatalogUsers
            .Any(cuInModel =>
                // comparing by value, not reference e.g.:
                cuInModel.Id == cuIdDb.Id))
        .ToList()) // required as you are modifying the list
    {
        _catalog.CatalogUsers.Remove(catalogUser);
    }

    //_context.Catalogs.Update(_catalog);// shouldn't be required due to entity tracking
    return await _context.SaveChangesAsync();
}

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