In a data-access layer that tracks loaded objects, what do the transient, managed, detached and removed states mean?
answer
- two questions: has a row, is watched
- new, managed, detached, removed
- detached still knows its key
- removed is tracked, not gone
- no tracked set means no states
basics
~20 sTransient means never stored and not watched. Managed means the tracked set holds it and will write its edits. Detached means it once was managed but its set has ended. Removed means a delete is planned.
solid answer
~50 sThe states answer two questions about one object: does a row exist for it, and is this layer watching it? **Transient** (new) exists only in memory, with no row and no tracking. **Managed** sits in the tracked set and is bound to a row the layer will insert or update when the unit of work writes. **Detached** carries a real key but its set is gone, so edits to it are ordinary in-memory edits nobody will write. **Removed** is still tracked, with a delete planned for its row. A save call moves new to managed, a delete call moves managed to removed, and ending the unit of work detaches everything at once. A layer with no tracked set - a query builder or a plain driver - has none of these states: it writes exactly what you tell it to.
go deeper
Learn to name all four states and one call that reaches each. The sentence to memorise is that transient and detached are untracked, managed and removed are tracked, and only a detached object already names a row.
Be able to walk a method line by line and say which state each object is in, including the transitions nobody calls: detachment when the unit of work ends, and a new child pulled in by a cascading link.
Show that you debug state, not symptoms. A lost edit, a duplicate row and a delete that never fired are all one question - which state was the object actually in when the write path ran - and you should say how you would prove it.
Frame it as a boundary decision. Where a codebase lets tracked objects escape into rendering, background work or caches, the states become ambient and unreviewable; deciding where objects must be untracked is worth more than any local fix.
A data-access layer that maps objects to rows normally keeps a **tracked set**: the objects it has loaded, or been handed, for the current unit of work. That set is the whole world the layer can write at the end. The lifecycle states are just the answer to two questions about a single object - *is there a row for it in the store?* and *is this layer watching it?* ## The four states - **Transient (new)** - the object exists only in memory. No row corresponds to it, and no layer is watching it. Dropping the reference costs nothing but the memory. - **Managed (persistent)** - the object is in the tracked set and bound to a row: either a row that already exists, or one the layer has planned to insert. Edits are noticed by whatever change detection the layer uses and will be written when the unit of work writes. - **Detached** - the object once was managed, so it usually still carries the key of a real row, but the set that tracked it has ended or released it. Edits to it are now ordinary in-memory edits: nobody will write them. - **Removed (deleted)** - still in the tracked set, but the layer has planned a delete for its row. It is a managed object with a pending deletion, not an object that has vanished. The pairing is worth saying out loud: transient and detached are both **untracked**, and managed and removed are both **tracked**. What separates transient from detached is store identity - the detached one names a row. ## The calls that move between them | From | To | What the application does | What the layer does | |---|---|---|---| | transient | managed | a save call | takes the object into the set and plans an insert | | managed | removed | a delete call | keeps tracking it and plans a delete | | managed | detached | closes the set, or evicts or clears | stops watching; unwritten edits stay in memory only | | detached | managed | a reattach or copy-in call | rejoins the object, or a copy of it, to a live set | | removed | managed | an undo or save-again call, where offered | cancels the planned delete | Not every layer offers every one of these, and the reattach row in particular differs enough between layers that it is a topic of its own. What is common across layers is the shape: **one call per deliberate transition, plus transitions nobody calls.** ## Transitions nobody calls Two moves usually happen without an explicit call on the object: 1. **Managed becomes detached when the unit of work ends.** Nothing is thrown, nothing is logged; the object simply stops being watched. This is the source of the classic "I set the field and nothing happened" bug - the setter ran on a detached object. 2. **Transient becomes managed by being reached.** If a managed object holds a link that the mapping declares as cascading, saving the parent can pull the newly constructed child into the set with it. ## What "managed" actually promises Managed promises *intent*, not a written row. A managed object's edits are queued; the row is unchanged until the layer emits the statement, and until the surrounding transaction commits, no other connection sees the change. A **removed** object is likewise still a normal object in memory - its fields are readable, its collections are traversable - right up to the point where the delete is sent and the unit of work closes. Candidates who picture "removed" as "gone" are surprised when the object still answers questions. *Exactly when* those queued statements are emitted is a separate question with its own rules, and it varies by layer. ## Layers with no states at all A query builder or a plain driver holds no tracked set. There is nothing to be managed in, so no object is ever detached, and no edit is ever written implicitly: you hand the layer a statement and it runs. That is not a poorer model, it is a different contract. The price is that insert-versus-update is your decision on every write; the benefit is that there is no invisible state to reason about, and no object can silently stop being watched. ## Why interviewers ask Because guessing the wrong state produces the three bugs everyone eventually ships: an edit that silently does nothing because the object was detached; an unexpected second row because a detached object was handed to a save that inferred "new"; and a delete that never happens because the object was never in the set. Being able to name the state an object is in at each line of a method is the skill actually being probed.
- What is the practical difference between a transient object and a detached one, given both are untracked?Store identity. A detached object names an existing row, so a write derived from it targets that row; a transient object names nothing, so any write must create a row. That difference is exactly what a generic save inspects when it guesses insert versus update, and it is why handing a detached object to a naive save can either update the right row or insert a duplicate.
- If an object becomes detached silently at the end of a unit of work, how do you catch edits that were lost?Make the boundary explicit rather than ambient: keep the write path inside a clearly delimited unit of work and do not hand still-tracked objects to code that runs after it. In review, treat a setter called on an object returned from a completed operation as suspect. Some layers can be configured to fail loudly on writes to untracked objects, which turns a silent loss into an error.
- Does a removed object stop being usable in memory once the delete is planned?No. It stays a normal object: its fields are readable and its links traversable until the unit of work ends. What changes is the plan the layer holds for its row. Some layers also treat re-saving it as cancelling the delete, so a removed object is not a one-way door in every layer.
A library book: never catalogued (transient), on loan and tracked to you (managed), catalogued but off the system after the branch closed (detached), and flagged for withdrawal but still on the shelf (removed).
saying these in an interview costs you the question
- Says a detached object's edits still get written at commit
- Thinks removed means the object disappears from memory at once
- Believes managed means the row has already been updated
- Cannot name a transition that happens without an explicit call
- Assumes every data-access layer has these four states