Card 02/ 07
Tracing One Entity Through the JPA Lifecycle
persist, find, detach and merge, with EntityManager.contains() checked after every step.
Following one Employee from new to managed (tracked by JPA, so changes are saved), to detached (no longer tracked), and back through merge() shows each state change for real. EntityManager.contains() answers whether the persistence context (JPA's record of the entities it is tracking in the current transaction) is watching a given object, so checking it after each operation shows the state instead of assuming it.
You need an EntityManager (em) inside a transaction, and an Employee entity with a generated id. Each step prints what contains() says:
Following one entity through the lifecycle
Transient, then persist()
Employee emp = new Employee("Alex");
System.out.println("before persist(): contains? " + em.contains(emp));
em.persist(emp);
System.out.println("after persist(): contains? " + em.contains(emp));A new object is not tracked. persist() makes it managed, so contains() changes from false to true.
Managed, then detach()
Employee found = em.find(Employee.class, emp.id);
System.out.println("found, contains? " + em.contains(found));
em.detach(found);
System.out.println("after detach(), contains? " + em.contains(found));find() returns the managed instance. detach() stops the tracking for that one object without touching the database.
Detached, then merge()
found.name = "merged-name";
Employee managed = em.merge(found);
System.out.println("merge() returned a " + (managed == found ? "SAME" : "DIFFERENT") + " instance");merge() copies the detached object's state into the persistence context and returns the managed instance, which is compared with the one passed in. found.name was changed first, so the returned instance carries the new name.
The output of all three steps, in order:
before persist(): contains? false
after persist(): contains? true
found, contains? true
after detach(), contains? false
merge() returned a DIFFERENT instanceEach line matches the state diagram: tracked after persist() and find(), untracked after detach(). The last line is the one to remember: merge() returned a different object from the one it was given. The detached found stays detached, and only the returned managed is tracked.
You know you have traced it correctly when every contains() result matches the state you predicted. So when an entity's changes seem to go missing, check contains() before anything else.
← → move through sections and cards