Enterprise Java Development@TOPIC@
Uni-directionalOnly one side ("owner") knows of the relationship
Uses the @OneToMany annotation
Defines mapping to database
Uses either @JoinColumn or @JoinTable
@JoinTable adds the foreign key to the child table and not to the owning entity class table in this uni-directional case
Bi-directionalBoth classes know of the relationship
Many side required to be owning side and maps relation to the database
Uses the @ManyToOne annotation
Uses either @JoinColumn or @JoinTable
Changes here change the database
One side required to be inverse and names the other entity's property
@OneToMany(mappedBy="owning-property")
Changes here do *not* change database
This example uses the @JoinColumn technique of inserting foreign key into child table of inverse entity class
No construct in child/inverse side to map to foreign key
Figure 57.3. One-to-Many Uni-directional Database Schema
create table ORMREL_INVENTORY (
/----> id bigint generated by default as identity,
| name varchar(255),
| primary key (id)
| )
| create table ORMREL_MEDIA (
| MEDIA_ID bigint generated by default as identity,
| title varchar(255),
`----- INVENTORY_ID bigint,
primary key (MEDIA_ID)
)
alter table ORMREL_MEDIA
add constraint FK639A68F4BCF517CD
foreign key (INVENTORY_ID)
references ORMREL_INVENTORYFigure 57.4. One-to-Many Uni-directional Database Java Mapping
@Entity @Table(name="ORMREL_INVENTORY")
public class Inventory {
@Id @GeneratedValue
private long id;
private String name;
@OneToMany(cascade={CascadeType.ALL})
/----- @JoinColumn(name="INVENTORY_ID")
| private Collection<Media> media = new ArrayList<Media>();
|
| @Entity @Table(name="ORMREL_MEDIA")
| public class Media {
| @Id @GeneratedValue @Column(name="MEDIA_ID")
`----> private long id;
Figure 57.5. One-to-Many Uni-directional Database Usage
ejava.examples.orm.rel.annotated.Inventory inventory = new Inventory();
inventory.setName("testLinkCreate");
em.persist(inventory);
for(int i=0; i<5; i++) {
ejava.examples.orm.rel.annotated.Media media = new Media();
em.persist(media);
log.info("created media:" + media);
inventory.getMedia().add(media);
}
log.info("created inventory:" + inventory);
Relationship formed when inverse side added to owning collection
Figure 57.6. One-to-Many Uni-directional Database Usage
Hibernate:
insert into ORMREL_INVENTORY (id, name)
values (null, ?)
Hibernate:
insert into ORMREL_MEDIA (MEDIA_ID, title)
values (null, ?)
-created media:ejava.examples.orm.rel.annotated.Media@5ae9fa73, id=1, title=null, authors(0)={}
...
Hibernate:
insert into ORMREL_MEDIA (MEDIA_ID, title)
values (null, ?)
-created media:Media@433a3459, id=5, title=null, authors(0)={}
-created inventory:Inventory@5b9e6638, id=1, name=testLinkCreate, media(5)={1,2,3,4,5,}
Hibernate:
update ORMREL_MEDIA
set INVENTORY_ID=?
where MEDIA_ID=?
...
Hibernate:
update ORMREL_MEDIA
set INVENTORY_ID=?
where MEDIA_ID=?The foreign key is in the inverse entity class table
No construct in inverse class maps to this foreign key column
Identical properties to @OneToOne annotation with the exception of no "optional" property
Figure 57.7. One-to-Many Bi-directional Example Database Schema
create table ORMREL_BORROWER (
+----> BORROWER_ID bigint not null,
| endDate date,
| startDate date,
| primary key (BORROWER_ID)
| )
| create table ORMREL_CHECKOUT (
| CHECKOUT_ID bigint generated by default as identity,
| outDate date,
| returnDate date,
`----- CHECKOUT_BID bigint not null,
primary key (CHECKOUT_ID)
)
alter table ORMREL_CHECKOUT
add constraint FK7F287E16C07B41F3
foreign key (CHECKOUT_BID)
references ORMREL_BORROWERFigure 57.8. One-to-Many Bi-directional Example Java Mapping
@Entity @Table(name="ORMREL_CHECKOUT")
public class Checkout {
@Id @GeneratedValue @Column(name="CHECKOUT_ID")
private long id;
+--> @ManyToOne(optional=false)
| @JoinColumn(name="CHECKOUT_BID")
+----- private Borrower borrower;
| |
| | @Entity @Table(name="ORMREL_BORROWER")
| | public class Borrower {
| | private static Log log = LogFactory.getLog(Borrower.class);
| | @Id @Column(name="BORROWER_ID")
`----> private long id;
|
| @OneToMany(mappedBy="borrower", //this relationship is owned by Checkout
| fetch=FetchType.LAZY) //try to limit what we get back
`--- private Collection<Checkout> checkouts = new ArrayList<Checkout>();
Figure 57.9. One-to-Many Bi-directional Example Usage (Create)
//get a borrower
Borrower borrower = em.find(Borrower.class, borrowerId);
assertNotNull(borrower);
assertTrue(borrower.getCheckouts().size() == 0);
//create 1st checkout
Checkout checkout = new Checkout(new Date());
checkout.setBorrower(borrower); //set owning side of the relation
borrower.addCheckout(checkout); //set inverse side of relation
//wrapper around - borower.getCheckouts().add(checkout)
em.persist(checkout); //persist owning side of the relation
Hibernate: -- query for the parent object, lazily loads child objects
select
borrower0_.BORROWER_ID as BORROWER1_15_0_,
borrower0_.endDate as endDate2_15_0_,
borrower0_.startDate as startDat3_15_0_
from ORMREL_BORROWER borrower0_
where borrower0_.BORROWER_ID=?
//get a borrower
//create a couple more
for(int i=0; i<5; i++) {
Checkout co = new Checkout(new Date());
co.setBorrower(borrower); //set owning side of the relation
borrower.addCheckout(co); //set inverse side of relation
em.persist(co); //persist owning side of the relation
}
Hibernate:
insert into ORMREL_CHECKOUT (CHECKOUT_ID, CHECKOUT_BID, outDate, returnDate)
values (null, ?, ?, ?)Figure 57.10. One-to-Many Bi-directional Example Usage (Verify)
//check the DB
em.flush(); em.clear();
Borrower borrower2 = em.find(Borrower.class, borrower.getId());
assertEquals(6, borrower2.getCheckouts().size());
Maps collection of simple data types to child table
Uses orphanRemoval for child values
Figure 57.11. Element Collection Example Database Schema
create table RELATIONEX_SUSPECT (
+----> id integer generated by default as identity,
| name varchar(32),
| primary key (id)
| )
| create table RELATIONEX_SUSPECT_ALIASES (
`----- SUSPECT_ID integer not null,
ALIAS varchar(32),
unique (SUSPECT_ID, ALIAS)
)
alter table RELATIONEX_SUSPECT_ALIASES
add constraint FK3FD160E6DE29C9CF
foreign key (SUSPECT_ID)
references RELATIONEX_SUSPECTFigure 57.12. Element Collection Example Database Java Mapping
@Entity
@Table(name="RELATIONEX_SUSPECT")
public class Suspect {
@Id @GeneratedValue
private int id;
@Column(length=32)
private String name;
@ElementCollection
@CollectionTable(
name="RELATIONEX_SUSPECT_ALIASES",
joinColumns=@JoinColumn(name="SUSPECT_ID"),
uniqueConstraints=@UniqueConstraint(columnNames={"SUSPECT_ID", "ALIAS"}))
@Column(name="ALIAS", length=32)
private Set<String> aliases;
Figure 57.13. Element Collection Example Database Usage
Suspect suspect = new Suspect();
suspect.setName("william");
em.persist(suspect);
suspect.getAliases().add("bill");
suspect.getAliases().add("billy");Link Table
Foreign key not placed in child table
Separate table used to realize relationship
Discussed in Join Tables section