Enterprise Java Development@TOPIC@
Determines how when related objects are retrieved
LAZY
Only parent object immediately retrieved -- child objects retrieved on demand
Can result in better performance when child data is not needed - unused objects not retrieved
Can result in poor performance when all child data is needed - retrieves objects one at a time rather than in bulk
Can result in lazy load exception if unloaded data accessed after it can no longer be retrieved from database
Can be simulated, on demand, using value or result class queries with JPA-QL
EAGER (the default)
Provider required to have loaded prior to transaction committing
Can result in better performance when all child data is needed
Can result in poor performance when no child data or limited child data is needed
Can result in poor performance when parent has multiple collections and equivalent of an "EAGER LAZY load" is performed before returning control back to the caller
Should never result in a lazy load exception
Can be simulated, on-demand, using "join fetch" queries with JPA-QL
Figure 58.1. fetch=LAZY Example Declaration
@OneToMany(mappedBy="borrower", //this relationship is owned by Checkout
fetch=FetchType.LAZY)
private Collection<Checkout> checkouts = new ArrayList<Checkout>();
@XxxToXxx Relationship annotated with fetch=LAZY property
Figure 58.2. fetch=LAZY Example Use
Borrower borrower2 = em.find(Borrower.class, borrower.getId());
log.info("found borrower: " + borrower.getName());
assertEquals(6, borrower2.getCheckouts().size());
Parent accessed, debug printed, and then child collection accessed
Figure 58.3. fetch=LAZY SQL Output
Hibernate: select applicant0_.id as id1_12_2_, applicant0_.APP_BORROWER as APP2_12_2_, applicant0_.APP_PERSON as APP3_12_2_, borrower1_.BORROWER_ID as BORROWER1_15_0_, borrower1_.endDate as endDate2_15_0_, borrower1_.startDate as startDat3_15_0_, person2_.PERSON_ID as PERSON1_24_1_, ... person2_.PERSON_PHOTO as PERSON5_24_1_ from ORMREL_APPLICANT applicant0_ left outer join ORMREL_BORROWER borrower1_ on applicant0_.APP_BORROWER=borrower1_.BORROWER_ID inner join ORMREL_PERSON person2_ on applicant0_.APP_PERSON=person2_.PERSON_ID where applicant0_.APP_BORROWER=? -found borrower: john smith Hibernate: select checkouts0_.CHECKOUT_BID as CHECKOUT4_15_1_, checkouts0_.CHECKOUT_ID as CHECKOUT1_16_1_, checkouts0_.CHECKOUT_ID as CHECKOUT1_16_0_, checkouts0_.CHECKOUT_BID as CHECKOUT4_16_0_, checkouts0_.outDate as outDate2_16_0_, checkouts0_.returnDate as returnDa3_16_0_ from ORMREL_CHECKOUT checkouts0_ where checkouts0_.CHECKOUT_BID=?
Debug for parent printed before child rows retrieved
Child rows retrieved when parent collection accessed
Figure 58.4. fetch=EAGER Example Declaration
@OneToMany(mappedBy="borrower", //this relationship is owned by Checkout
fetch=FetchType.EAGER)
private Collection<Checkout> checkouts = new ArrayList<Checkout>();
Figure 58.5. fetch=EAGER Example Use
Borrower borrower3 = em.find(Borrower.class, borrowerId);
log.info("found borrower: " + borrower.getName());
assertEquals(0,borrower3.getCheckouts().size());
Same as fetch=LAZY case
Figure 58.6. fetch=EAGER SQL Output
Hibernate: select applicant0_.id as id1_12_3_, applicant0_.APP_BORROWER as APP2_12_3_, applicant0_.APP_PERSON as APP3_12_3_, borrower1_.BORROWER_ID as BORROWER1_15_0_, borrower1_.endDate as endDate2_15_0_, borrower1_.startDate as startDat3_15_0_, checkouts2_.CHECKOUT_BID as CHECKOUT4_15_5_, checkouts2_.CHECKOUT_ID as CHECKOUT1_16_5_, checkouts2_.CHECKOUT_ID as CHECKOUT1_16_1_, checkouts2_.CHECKOUT_BID as CHECKOUT4_16_1_, checkouts2_.outDate as outDate2_16_1_, checkouts2_.returnDate as returnDa3_16_1_, person3_.PERSON_ID as PERSON1_24_2_, ... person3_.PERSON_PHOTO as PERSON5_24_2_ from ORMREL_APPLICANT applicant0_ left outer join ORMREL_BORROWER borrower1_ on applicant0_.APP_BORROWER=borrower1_.BORROWER_ID left outer join ORMREL_CHECKOUT checkouts2_ on borrower1_.BORROWER_ID=checkouts2_.CHECKOUT_BID inner join ORMREL_PERSON person3_ on applicant0_.APP_PERSON=person3_.PERSON_ID where applicant0_.APP_BORROWER=? -found borrower: john smith
Child objects fetched with parent
Access to child collection occurs after all children fetched
Automatically cause persistence commands to be repeated on related objects
Figure 58.7.
@Entity
@Table(name="RELATIONEX_LICAPP")
public class LicenseApplication {
@Id @GeneratedValue
private int id;
@Temporal(TemporalType.TIMESTAMP)
private Date updated;
@OneToOne(optional=false, fetch=FetchType.EAGER,
cascade={
CascadeType.PERSIST,
CascadeType.DETACH,
CascadeType.REMOVE,
CascadeType.REFRESH,
CascadeType.MERGE
})
private License license;
PERSIST
Related entities persisted when this entity is passed to em.persist()
DETACH
Related entities detached from persistence unit when this entity passed to em.detach()
REMOVE
Related entities deleted from database when this entity passed to em.remove()
REFRESH
Related entities refreshed with state of database when this entity passed to em.refresh()
MERGE
Related entities update state of database when this entity is passed to em.merge()
Automatic removal of an object who's sole purpose is to support a related object that may dereference it
Related to cascade=REMOVE but the triggering object is not being deleted
Supported in the following relationships
@OneToOne
@OneToMany
Figure 58.8. OrphanRemoval Example Declaration
@Entity
@Table(name="RELATIONEX_ATTENDEE")
public class Attendee {
@Id @GeneratedValue
private int id;
//orphanRemoval will take care of dereference and DELETE from dependent Attendee
@OneToOne(cascade=CascadeType.PERSIST, orphanRemoval=true)
private Residence residence;
Figure 58.10. OrphanRemoval Database Interaction
Hibernate: update RELATIONEX_ATTENDEE set name=?, residence_id=? where id=? Hibernate: delete from RELATIONEX_RESIDENCE where id=?
Attendee.residence_id set to null
Orphaned residence deleted
Use fetch=EAGER when always accessing related objects together
Use fetch=LAZY when commonly access one object without accessing related objects
Use JPA-QL when encountering corner cases that violate default mapping
Cascades can be used to automate persistence actions on an entire object graph
OrphanRemoval can used to automatically delete dereferenced objects that have no use outside the scope of its owning relation