Enterprise Java Development@TOPIC@

Chapter 56. One-to-One Relationships

56.1. One-to-One: Uni-directional
56.2. @OneToOne Annotation
56.3. @JoinColumn Annotation
56.4. @JoinColumns Annotation
56.5. One-to-One: Bi-directional
56.6. Bi-directional Relationships and Ownership
56.7. Other Topics
56.8. Summary

Figure 56.1. One-to-One Uni-directional

One-to-One Uni-directional

Figure 56.2. One-to-One Bi-directional

One-to-One Bi-directional

Uni-directional

Only one class ("owner") knows of the relationship

  • Uses the @OneToOne annotation

  • Defines mapping to database

    • Uses either @JoinColumn or @JoinTable

Bi-directional

Both classes know of the relationship

  • Both classes use the @OneToOne annotation

  • One class is considered the owner and maps relation to the database

    • Uses either @JoinColumn or @JoinTable

    • Changes here change the database

  • One class is considered the inverse and names the other entity's property

    • @OneToOne(mappedBy="owning-property")

    • Changes here do *not* change database


  • Relation realized through a foreign key

  • Foreign key represented by a separate column

  • Foreign key from owning entity table references primary key of inverse entity table


Figure 56.5. One-to-One Uni-directional Usage

//create the owning side 

ejava.examples.orm.rel.annotated.Person person = new Person();
person.setFirstName("john");
person.setLastName("doe");
person.setPhone("410-555-1212");
//create the inverse side 
ejava.examples.orm.rel.annotated.Photo photo = new Photo();        
photo.setImage(image);        
//add photo to person and persist object tree
person.setPhoto(photo); //this sets the FK in person
log.info("added photo to person:" + person);
em.persist(person);        
assertTrue("personId not set", person.getId() != 0);
assertTrue("photoId not set", photo.getId() != 0);
log.info("created person:" + person);
-added photo to person:Person@1201f5bc, id=0, name=john doe, phone=410-555-1212, 
    photo=Photo@130b5045, id=0. image=46080 bytes
Hibernate:
    insert into ORMREL_PHOTO (PHOTO_ID, image) 
    values (null, ?)
Hibernate:
    insert into ORMREL_PERSON (PERSON_ID, firstName, lastName, phone, PERSON_PHOTO) 
    values (null, ?, ?, ?, ?)
-created person:Person@1201f5bc, id=1, name=john doe, phone=410-555-1212, 
        photo=Photo@130b5045, id=1. image=46080 bytes
//verify what we can get from DB

em.flush(); em.clear();
Person person2 = em.find(Person.class, person.getId());
assertNotNull(person2);
assertNotNull(person2.getPhoto());
log.info("found person:" + person2);
Hibernate:
    select
        person0_.PERSON_ID as PERSON1_24_0_,
        person0_.firstName as firstNam2_24_0_,
        person0_.lastName as lastName3_24_0_,
        person0_.phone as phone4_24_0_,
        person0_.PERSON_PHOTO as PERSON5_24_0_ 
    from ORMREL_PERSON person0_ 
    where person0_.PERSON_ID=?
Hibernate:
    select
        photo0_.PHOTO_ID as PHOTO1_25_0_,
        photo0_.image as image2_25_0_ 
    from ORMREL_PHOTO photo0_ 
    where photo0_.PHOTO_ID=?
-found person:Person@29564bb9, id=1, name=john doe, phone=410-555-1212, 
    photo=Photo@785e7845, id=1. image=46080 bytes

optional:boolean (default=true)

Designates whether relation is required. Default is true.

fetch:FetchType (default=EAGER)

Use EAGER or LAZY fetching of relationship when loading this entity. More of coverage of fetch in Fetching section

orphanRemoval:boolean (default=false)

Remote entity only exists for use by this relation. Automatically delete when relation terminated.

cascade:CascadeType[] (default=none)

Perform actions taken on this entity on related entity

targetEntity:Class

Define type for related class (if related Java type over-generalized)

mappedBy:String

Used by inverse side to specify owning entity property that maps relation to DB

Defines a foreign key mapping

Used to define multiple @JoinColumns when using composite foreign keys

@OneToOne

@JoinColumns({ //defines an array of @JoinColumns
    @JoinColumn(...),
    @JoinColumn(...)    
})

  • No additional foreign key used to satisfy the bi-directional aspect of relation



Note

Notice only owning entity table is updated when relationship formed.

Figure 56.9. One-to-One Uni-directional Example Usage (cont.)

        

        //locate them from DB
        em.flush(); em.clear();
        Applicant applicant3 = em.find(Applicant.class, applicant.getId());
        Borrower borrower3 = em.find(Borrower.class, borrower.getId());
        assertEquals(applicant.getId(), borrower3.getApplication().getId());
        assertEquals(borrower.getId(), applicant3.getBorrower().getId());
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_,
        ...
    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_.id=?
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_,
        ...
    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=?
        -

  • Notice the extra joins that occur with default fetch mode=EAGER

  • inner joins used for optional=false relationships

  • left outer joins used for optional=true relationships