In the project on ASP.Net Core second version there is a Person entity with one-to-many connections between Email , Phone and Address entities. In the view, when editing a person, Email , Phone and Address entities are added dynamically and without saving to the database.
Interconnection scheme in DB
When saving a person, all information is stored in the database without problems: both the person and the added addresses with the phones.
The problem is with the deletion, for example email address. On the controller side, I get an instance of Person with the correct ICollection<Email> (for example, without a remote email address), then saving to the database occurs without errors, but only changes in the properties of the person are displayed in the database, i.e. Email address is not deleted.
Therefore, at the moment in the controller I do this:
var _emails = await _context.Email .Where(e => e.PersonId == person.Id && person.Emails .Where(i => i.Id == e.Id) .Count() == 0) .ToListAsync(); _context.Email.RemoveRange(_emails); _context.Person.Update(person); await _context.SaveChangesAsync(); But there are doubts that I am doing the right thing because such an approach looks somehow "clumsy."
How to save an entity with all transferred entities in the collection? Is there a way to automatically remove entities that are not passed to the collection of related objects?
Model:
namespace ProjectNS.Models { public partial class Ctx : DbContext { public virtual DbSet<Address> Address { get; set; } public virtual DbSet<Email> Email { get; set; } public virtual DbSet<Person> Person { get; set; } public virtual DbSet<Phone> Phone { get; set; } protected override void OnModelCreating(ModelBuilder modelBuilder) { // Address и Phone пропущены для экономии места (выглядят аналогично) modelBuilder.Entity<Email>(entity => { // Описание свойств пропущено для экономии места entity.HasOne(d => d.Person) .WithMany(p => p.Emails) .HasForeignKey(d => d.PersonId) .HasConstraintName("FK_Email_Person"); }); modelBuilder.Entity<Person>(entity => { // Описание свойств пропущено для экономии места entity.HasOne(d => d.CompanyNavigation) .WithMany(p => p.Person) .HasForeignKey(d => d.CompanyId) .OnDelete(DeleteBehavior.Cascade) .HasConstraintName("FK_Person_Company"); }); } } public partial class Person { public int Id { get; set; } // ничего особенного public ICollection<Address> Addresses { get; set; } public ICollection<Phone> Phones { get; set; } public ICollection<Email> Emails { get; set; } } // Address и Phone пропущены для экономии места (выглядят аналогично) public partial class Email { public int Id { get; set; } // ничего особенного public int? PersonId { get; set; } public Person Person { get; set; } } } Controller:
namespace ProjectNS.Controllers { public class PeopleController : Controller { private readonly Ctx _context; public PeopleController(Ctx context) { _context = context; } // Другие методы пропущены для экономии места [HttpPost] [ValidateAntiForgeryToken] public async Task<IActionResult> Edit(int id, [Bind("Id,...,Emails,Phones,Addresses")] Person person) { if (id != person.Id) { return NotFound(); } if (ModelState.IsValid) { try { // Вот здесь начинается "танец с бубном" // для удаления несуществующих сущностей из БД var _emails = await _context.Email .Where(e => e.PersonId == person.Id && person.Emails .Where(i => i.Id == e.Id) .Count() == 0) .ToListAsync(); _context.Email.RemoveRange(_emails); _context.Person.Update(person); await _context.SaveChangesAsync(); } catch (DbUpdateConcurrencyException) { if (!PersonExists(person.Id)) { return NotFound(); } else { throw; } } return RedirectToAction(nameof(Index)); } ViewData[nameof(Person.CompanyId)] = new SelectList(_context.Company, nameof(Company.Id), nameof(Company.Name), person.CompanyId); return View(person); } } } 
EmailfromPerson, then the changes are saved. When adding a newEmail, everything is fine too. And when deleting related entities, the changes are not displayed in the database. About the "detachment" can be more detailed? - XelaNimeddb.Emails.RemoveRange(db.Emails.Where(x=>x.PErsonId == null));are simply deleted by thedb.Emails.RemoveRange(db.Emails.Where(x=>x.PErsonId == null));proceduredb.Emails.RemoveRange(db.Emails.Where(x=>x.PErsonId == null));How does your Email record look like if you in the Person that it was, updated the collection? - Dmitry Polyanin