Java Persistence API (JPA) and Entity Mapping
Domain 5 tests object-relational mapping decisions and persistence-context behaviour: relationship ownership, fetch and cascade defaults, and the difference between persist and merge.
Mapping
- An @Entity needs a no-arg constructor, a non-final class and an @Id. @GeneratedValue strategies are AUTO, IDENTITY, SEQUENCE and TABLE.
- The owning side holds the foreign key. mappedBy appears only on the inverse side and names the field on the owning side. @ManyToOne defaults to EAGER while collections default to LAZY.
- Cascade types are PERSIST, MERGE, REMOVE, REFRESH, DETACH and ALL; orphanRemoval deletes children removed from a collection.
- Inheritance strategies: SINGLE_TABLE (the default, with a discriminator column), JOINED, TABLE_PER_CLASS. @ElementCollection maps value collections that are not entities.
Persistence context
- persist() makes a transient instance managed; merge() copies state onto a managed instance and returns it, leaving the argument detached.
- find() checks the context then the database; getReference() returns a lazy proxy that throws EntityNotFoundException on first access when the row is missing.
- A transaction-scoped context ends at commit; EXTENDED contexts are legal only on stateful session beans.
- @Version enables optimistic locking and a conflicting update raises OptimisticLockException.
JPA 2.1 additions
Stored procedure queries, standardised schema generation properties, attribute converters (@Converter with autoApply), entity graphs for fetch planning, and unsynchronised persistence contexts.
Worked example
An Author has many Books and Book owns the join column. With @OneToMany(mappedBy="author") on Author and @ManyToOne on Book, saving requires book.setAuthor(author); adding the book to the Author collection alone never updates the foreign key because only the owning side writes it.
Traps
- Cascading REMOVE from a parent to a child that other entities reference.
- Assuming lazy associations load after the EntityManager closes, causing LazyInitializationException.
- Calling merge() for a new entity and expecting the passed instance to become managed.