How do you update a disconnected entity graph in EF Core (Web API)?
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
GraphDiffautomate this; EF Core'sChangeTracker.TrackGraphis the low-level hook.