How do you update a disconnected entity graph in EF Core (Web API)?

Entity Framework & EF Core Persistence Advanced 3–5 Yrs5+ Yrs Scenario 1 min read

Quick Answer

The safe pattern: load the existing entity with its children, then apply the incoming DTO onto it — update matched children, add new ones, remove children no longer present — and SaveChanges. Calling Update() on a detached graph marks everything modified, can't detect deletions, and fights concurrency.

The mistake is calling context.Update on the object that came from the request body — it marks every field dirty, it can't tell that a child was removed, and it bypasses concurrency. What I do instead is load the current entity from the database including its children, then walk the incoming DTO and reconcile: update the children that match by id, add the ones that are new, and remove the existing children whose ids aren't in the payload any more. Then SaveChanges. Because I loaded the real entity, the rowversion is there and concurrency checking works.

  • var order = await db.Orders.Include(o => o.Lines).SingleAsync(o => o.Id == dto.Id);
  • Copy scalar fields: order.Notes = dto.Notes;.
  • For each incoming line: if it has an id and matches, update it; if no id, order.Lines.Add(new Line(...)).
  • For each existing line whose id isn't in the DTO: db.Lines.Remove(line) (or mark as deleted).
  • Concurrency token comes along for free because you loaded the real entity.
  • Libraries like GraphDiff automate this; EF Core's ChangeTracker.TrackGraph is the low-level hook.