Java Persistence: Object Relationship Mapping - PowerPoint PPT Presentation

1 / 68
About This Presentation
Title:

Java Persistence: Object Relationship Mapping

Description:

... able to map a relationships between classes to the database using class ... create one (inverse side) ejava.examples.orm.rel.annotated.Media media = new Media ... – PowerPoint PPT presentation

Number of Views:77
Avg rating:3.0/5.0
Slides: 69
Provided by: webdev
Category:

less

Transcript and Presenter's Notes

Title: Java Persistence: Object Relationship Mapping


1
Java PersistenceObject RelationshipMapping
2
Goals
  • Be able to map a relationships between classes to
    the database using class annotations
  • coverage of ORM descriptors can be found in text
    or JPA Spec
  • Be able to navigate relationships between objects
    persisted to the database using get/set API calls
    instead of SQL

3
Objectives
  • Relationship Sides (owning and inverse)
  • Relationship Types
  • OneToOne
  • ManyToOne
  • OneToMany
  • ManyToMany
  • Relationship Directions
  • uni-directional
  • bi-directional
  • Collection Types
  • FetchType
  • CascadeType

4
OneToOne
  • Uni-directional
  • Bi-Directional

5
OneToOne
  • Uni-directional
  • only one class (owner) knows of the
    relationship
  • uses _at_OneToOne annotation
  • this class defines the mapping to the database
  • may use _at_JoinColumn or _at_JoinTable annotation
  • Bi-Directional
  • both classes know of the relationship
  • use _at_OneToOne annotation
  • one class (owner) defines the mapping to the
    database
  • may use _at_JoinColumn or _at_JoinTable annotation
  • the other class (inverse side) names the
    owner's property that defines the relationship
  • uses _at_OneToOne(mappedByremote property)

6
OneToOne Uni-directional Example DB Schema
  • create table ORMREL_PHOTO (PHOTO_ID bigint
    generated by default as identity (..., image
    longvarbinary, primary key (PHOTO_ID))
  • create table ORMREL_PERSON (PERSON_ID bigint
    generated by default as identity (..., firstName
    varchar(255), lastName varchar(255), phone
    varchar(255), PERSON_PHOTO bigint, primary key
    (PERSON_ID))
  • alter table ORMREL_PERSON add constraint
    FK14D7C425DCCB1C0D foreign key (PERSON_PHOTO)
    references ORMREL_PHOTO

7
OneToOne Uni-directional Example Java Mapping
  • _at_Entity _at_Table(name"ORMREL_PHOTO")
  • public class Photo
  • _at_Id _at_GeneratedValue _at_Column(name"PHOTO_ID")
  • private long id
  • _at_Lob
  • private byte image
  • _at_Entity _at_Table(name"ORMREL_PERSON")
  • public class Person
  • _at_Id _at_GeneratedValue _at_Column(name"PERSON_ID")
  • private long id
  • private String firstName
  • private String lastName
  • private String phone
  • _at_OneToOne(cascadeCascadeType.ALL,
  • fetchFetchType.LAZY)
  • _at_JoinColumn(name"PERSON_PHOTO")
  • private Photo photo

There is no inverse relationship definition for
uni-directional relationships
Owning side uses a JoinColumn to name the
foreign key column for the relationship
8
_at_OneToOne Annotation
  • public interface OneToOne extends ...
  • Class targetEntity() default void.class
  • entity class related to
  • can usually be determined by property type
  • CascadeType cascade() default
  • defines which persistence operations to cascade
    to related object
  • FetchType fetch() default EAGER
  • hint to provider as to whether related object
    necessary
  • boolean optional() default true
  • states whether value of relationship can be null
  • String mappedBy() default
  • only used in bi-directional relationships on the
    inverse side
  • names remote property in owning class that
    defines mapping to DB

9
FetchType (hint)
  • EAGER
  • related object is always instantiated from the
    database when this object is instantiated
  • LAZY
  • related object not instantiated from database
    when this object is instantiated
  • proxy is acting as a place-holder
  • undefined implementation by spec
  • byte code manipulation of entity class required
    option of Java EE environment
  • post-compilation step option for Java SE
    environment
  • dynamic proxy classes
  • object is fetched and instantiated when proxy
    accessed and object is still attached to the
    persistence context
  • exception thrown (undefined by spec) if proxy
    accessed after object is detached from
    persistence context

10
_at_JoinColumn Annotation
  • public interface JoinColumn extends ...
  • very similar to _at_Column annotation
  • String name() default
  • name of database column for foreign key
  • String referencedColumnName() default (PK
    column of related object)
  • used to reference a non-primary key field in
    related object
  • must be unique value in OneToOne relationship
  • boolean unique() default false
  • is foreign key unique within table
  • boolean nullable() default true
  • is foreign key allowed to be null
  • boolean insertable() default true
  • is foreign key present on create
  • boolean updatable() default true
  • is foreign key included in updates
  • String columnDefinition() default
  • exact DDL for column type
  • String table() default
  • used for multi-table mappings

11
_at_JoinColumns Annotation
  • public interface JoinColumns extends ...
  • public abstract JoinColumn value()
  • defines array of foreign key columns for
    composite keys
  • Example Usage
  • _at_OneToOne
  • _at_JoinColumns(
  • _at_JoinColumn(...),
  • _at_JoinColumn(...)
  • )

12
OneToOne Uni-directional Example Usage
  • //create 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 anytime
  • person.setPhoto(photo) //will set the FK in
    person
  • //write person to DB persist configured to
    cascade to photo
  • em.persist(person)
  • //verify what we can get from DB
  • em.flush() //FK physically written at
    this point
  • em.clear()

13
Primary Key Join Example DB Schema
  • create table ORMREL_BORROWER (BORROWER_ID bigint
    not null, startDate date, endDate date,
    primary key (BORROWER_ID))
  • create table ORMREL_PERSON (PERSON_ID bigint
    generated by default as identity (..., firstName
    varchar(255), lastName varchar(255), phone
    varchar(255), PERSON_PHOTO bigint, primary key
    (PERSON_ID))
  • alter table ORMREL_BORROWER
  • add constraint FKA0973E32F113D9BA
  • foreign key (BORROWER_ID)
  • references ORMREL_PERSON

14
Primary Key Join
  • public interface PrimaryKeyJoinColumn extends
    ...
  • used instead of JoinColumn to define a primary
    key join between this and referenced object
  • String name() default
  • used when this class defines a composite primary
    key
  • names primary key column in this class' table
    that references related object
  • String referencedColumnName() default
  • used to specify column foreign key is referencing
  • will default to PK field for related object's
    table
  • String columnDefinition() default
  • specific DDL for column definition

15
Primary Key Join Example Java Mapping
  • _at_Entity _at_Table(name"ORMREL_BORROWER")
  • public class Borrower
  • _at_Id _at_Column(name"BORROWER_ID")
  • private long id
  • _at_OneToOne(fetchFetchType.LAZY,
    optionalfalse,
  • cascadeCascadeType.PERSIST,
  • CascadeType.REFRESH,
  • CascadeType.MERGE)
  • _at_PrimaryKeyJoinColumn
  • private Person identity
  • _at_Entity
  • _at_Table(name"ORMREL_PERSON")
  • public class Person
  • _at_Id _at_GeneratedValue _at_Column(name"PERSON_ID")
  • private long id

16
OneToOne Bi-directional Example DB Schema
  • create table ORMREL_BORROWER (BORROWER_ID bigint
    not null, startDate date, endDate date,
    primary key (BORROWER_ID))
  • create table ORMREL_APPLICANT (id bigint
    generated by default as identity, APP_PERSON
    bigint not null, APP_BORROWER bigint, primary
    key (id), unique (APP_PERSON))
  • alter table ORMREL_APPLICANT add constraint
    FKD186081242E2AFD5 foreign key (APP_PERSON)
    references ORMREL_PERSON

RDBMSes are insensitive to direction. Therefore
once a foreign key is defined on one side or the
other, it can be used from either direction
17
OneToOne Bi-directional Example Java Mapping
  • _at_Entity _at_Table(name"ORMREL_BORROWER")
  • public class Borrower
  • private static Log log LogFactory.getLog(Bor
    rower.class)
  • _at_Id _at_Column(name"BORROWER_ID")
  • private long id
  • _at_OneToOne(fetchFetchType.LAZY,
  • optionaltrue,
  • mappedBy"borrower") private
    Applicant application
  • _at_Entity _at_Table(name"ORMREL_APPLICANT")
  • public class Applicant
  • _at_Id _at_GeneratedValue
  • private long id
  • _at_OneToOne(optionaltrue)
  • _at_JoinColumn(name"APP_BORROWER")
  • private Borrower borrower

Inverse-side of relationship defines remote
property that defines the database mapping
Owning side uses a JoinColumn to name the
foreign key column for the relationship
18
OneToOne Bi-directional Example Usage
  • Applicant applicant2 em.find(Applicant.class,
    applicantId)
  • Borrower borrower2 em.find(Borrower.class,
    borrowerId)
  • //form relationship
  • borrower2.setApplication(applicant2) //set
    inverse side
  • applicant2.setBorrower(borrower2) //set
    owning side
  • em.flush()
  • em.clear()
  • //locate them from DB
  • Applicant applicant3 em.find(Applicant.class,
    applicantId)
  • Borrower borrower3 em.find(Borrower.class,
    borrowerId)
  • assertEquals(applicant3.getId(),
    borrower3.getApplication().getId())
  • assertEquals(borrower3.getId(),
    applicant3.getBorrower().getId())

Must manually set both sides of a
bi-directional relationship
19
Bi-directional Relationships and Ownership
  • Only changes made to owning side impact database
  • persist
  • update
  • remove
  • Actions taken on owning side not automatically
    propagated to inverse side
  • must either
  • manually update inverse side
  • design classes to handle propogation
  • refresh object if proper state in database

20
Bi-directional Relationships and Ownership Example
  • Borrower borrower em.find(Borrower.class,
    borrowerId)
  • Applicant applicant em.find(Applicant.class,
    applicantId)
  • assertNull("borrower has unexpected applicant"
  • borrower.getApplication(),
  • borrower.getApplication())
  • assertNull("applicant has unexpected borrower"
  • applicant.getBorrower(),
  • applicant.getBorrower())
  • //set ONLY the inverse side of the
    relationship
  • borrower.setApplication(applicant)
  • assertNotNull("borrower does not have applicant",
  • borrower.getApplication())
  • assertNull("applicant has unexpected borrower"
  • applicant.getBorrower(),
  • applicant.getBorrower())

Not setting owning side will cause no later
change to DB
Set on either side does NOT get automatically
propagated to other side
21
Bi-directional Relationships and Ownership
Example (cont.)
  • em.getTransaction().commit()
  • em.clear()
  • assertFalse("borrower was managed",
    em.contains(borrower))
  • assertFalse("application was managed",
    em.contains(applicant))
  • borrower em.find(Borrower.class, borrowerId)
  • applicant em.find(Applicant.class,
    applicantId)
  • //verify that relationship from cache
    never written to DB
  • assertNull("borrower has unexpected applicant"
  • borrower.getApplication(),
  • borrower.getApplication())
  • assertNull("applicant has unexpected borrower"
  • applicant.getBorrower(),
  • applicant.getBorrower())

Not setting owning side caused change to be lost
on next refresh
22
Bi-directional Relationships and Ownership Example
  • Borrower borrower em.find(Borrower.class,
    borrowerId)
  • Applicant applicant em.find(Applicant.class,
    applicantId)
  • assertNull("borrower has unexpected applicant"
  • borrower.getApplication(),
  • borrower.getApplication())
  • assertNull("applicant has unexpected borrower"
  • applicant.getBorrower(),
  • applicant.getBorrower())
  • //set ONLY the owning side of the
    relationship
  • applicant.setBorrower(borrower)
  • assertNull("borrower has unexpected applicant",
  • borrower.getApplication())
  • assertNotNull("applicant does not have borrower"
  • applicant.getBorrower(),
  • applicant.getBorrower())

Not setting inverse side no impact to DB
Set on owning side will take care of updating DB
23
Bi-directional Relationships and Ownership
Example (cont.)
  • em.getTransaction().commit()
  • em.clear()
  • assertFalse("borrower was managed",
    em.contains(borrower))
  • assertFalse("application was managed",
    em.contains(applicant))
  • borrower em.find(Borrower.class, borrowerId)
  • applicant em.find(Applicant.class,
    applicantId)
  • //verify that relationship from cache
    written to DB
  • assertNotNull("borrower did not have applicant"
  • borrower.getApplication(),
  • borrower.getApplication())
  • assertNotNull("applicant did not have borrower"
  • applicant.getBorrower(),
  • applicant.getBorrower())

Changes now correctly reflected in DB
24
ManyToOne
  • Uni-directional
  • Many side is only class (owner) that knows of
    the relationship
  • uses _at_ManyToOne annotation
  • this class defines the mapping to the database
  • may use _at_JoinColumn or _at_JoinTable annotation
  • Bi-directional
  • Many side required to own relationship
  • One side (inverse side) names the owner's
    property that defines the relationship
  • may use _at_OneToMany(mappedByremote property)

25
ManyToOne
  • Uni-directional
  • Bi-Directional

26
ManyToOne Uni-directional Example DB Schema
  • create table ORMREL_MEDIA (MEDIA_ID bigint
    generated by default as identity, title
    varchar(255), primary key (MEDIA_ID))
  • create table ORMREL_MEDIACOPY (COPY_NO integer
    not null, MEDIACOPY_MID bigint not null,
    primary key (COPY_NO, MEDIACOPY_MID))
  • alter table ORMREL_MEDIACOPY add constraint
    FKCDB47669F152B359 foreign key (MEDIACOPY_MID)
    references ORMREL_MEDIA

Many side defines foreign key to one side
In this case, foreign key is part of primary
key
27
ManyToOne Uni-directional Example Java Mapping
There is no inverse relationship definition for
uni-directional relationships
  • _at_Entity _at_Table(name"ORMREL_MEDIA")
  • public class Media
  • _at_Id _at_GeneratedValue _at_Column(name"MEDIA_ID")
  • private long id
  • _at_Entity _at_Table(name"ORMREL_MEDIACOPY")
  • _at_IdClass(MediaCopyPK.class)
  • public class MediaCopy
  • //use m2o to have media automatically
    associated
  • _at_ManyToOne(optionalfalse)
  • _at_JoinColumn(
  • name"MEDIACOPY_MID",
  • nullablefalse, updatablefalse)
  • public Media getMedia()
    return media
  • private void setMedia(Media media)
    this.media media

Owning side uses a JoinColumn to name the
foreign key column for the relationship
28
_at_ManyToOne Annotation
  • public interface ManyToOne extends ...
  • Class targetEntity() default void.class
  • entity type to map target of relation
  • can be determined by provider from property type
  • CascadeType cascade() default
  • defines which persistence operations will also
    apply to related object
  • FetchType fetch() default EAGER
  • hint to provider whether related object is
    necessary
  • boolean optional() default true
  • is foreign key allowed to be null

29
ManyToOne Uni-directional Example Usage
  • //create one (inverse side)
  • ejava.examples.orm.rel.annotated.Media media
    new Media()
  • media.setTitle("EJB3")
  • em.persist(media)
  • assertTrue(media.getId() ! 0)
  • //create some copies (owning side)
  • for(int i0 ilt5 i)
  • ejava.examples.orm.rel.annotated.MediaCopy mc
  • new MediaCopy(media, i)
  • assertNotNull(mc.getMedia())
  • assertEquals(i, mc.getCopyNo())
  • //must manually persist since no cascade
    defined from Media
  • em.persist(mc)
  • log.info("created copy" mc)

Owning side property set in ctor()
30
ManyToOne Uni-directional Example Usage (cont.)
  • em.flush()
  • em.clear()
  • //verify media copy from database provides media
    object
  • for(int i0 ilt5 i)
  • //media copy uses a composite primary key
  • ejava.examples.orm.rel.MediaCopyPK pk
  • new MediaCopyPK(media.getId(), i)
  • MediaCopy mc em.find(MediaCopy.class, pk)
  • assertNotNull("media copy not found" pk,
    mc)
  • assertEquals("unexpected mediaId"
    mc.getMediaId(),
  • mc.getMediaId(), media.getId())
  • assertEquals("unexpected copyNo"
    mc.getCopyNo(),
  • mc.getCopyNo(), i)
  • assertNotNull("no media resolved",
    mc.getMedia())

31
Issues Mapping Composite Key Column
  • public class MediaCopyPK implements Serializable
  • _at_Column(name"COPY_NO") public int
    getCopyNo() ...
  • _at_Column(name"MEDIACOPY_MID") public long
    getMediaId() ...
  • _at_Entity _at_Table(name"ORMREL_MEDIACOPY")
  • _at_IdClass(MediaCopyPK.class)
  • public class MediaCopy
  • public int getCopyNo()
    return copyNo
  • private void setCopyNo(int copyNo)
    this.copyNo copyNo
  • //this property is used for the composite
    primary key
  • public long getMediaId()
    return mediaId
  • private void setMediaId(long mediaId)
  • this.mediaId mediaId

create table ORMREL_MEDIACOPY (COPY_NO integer
not null, MEDIACOPY_MID bigint not null,
primary key (COPY_NO, MEDIACOPY_MID))
Provider requires a separate property to map
entire foreign key.
32
Issues Mapping Composite Key Column
  • _at_ManyToOne
  • _at_JoinColumn(name"MEDIACOPY_MID")
  • public Media getMedia()
    return media
  • _at_SuppressWarnings("unused")
  • private void setMedia(Media media)
    this.media media
  • javax.persistence.PersistenceException
    org.hibernate.MappingException Repeated column
    in mapping for entity ejava.examples.orm.rel.anno
    tated.MediaCopy column MEDIACOPY_MID (should be
    mapped with insert"false" update"false")
  • _at_ManyToOne
  • _at_JoinColumn(name"MEDIACOPY_MID",
  • insertablefalse,updatablefalse)
  • public Media getMedia()
    return media

alter table ORMREL_MEDIACOPY add constraint
FKCDB47669F152B359 foreign key (MEDIACOPY_MID)
references ORMREL_MEDIA
Foreign key for the relationship is mapped to
same column as primary key
Now updates to the media property do not
attempt to update the FK column, which is also a
PK column.
33
ManyToOne Bi-directional Example DB Schema
  • create table ORMREL_BORROWER (BORROWER_ID bigint
    not null, startDate date, endDate 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_BORROWER

Many side defines foreign key to one side
34
ManyToOne Bi-directional Example Java Mapping
  • _at_Entity _at_Table(name"ORMREL_BORROWER")
  • public class Borrower
  • _at_Id _at_Column(name"BORROWER_ID")
  • private long id
  • _at_OneToMany(mappedBy"borrower",
  • fetchFetchType.LAZY)
  • private CollectionltCheckoutgt checkouts
    new ArrayListltCheckoutgt()
  • _at_Entity _at_Table(name"ORMREL_CHECKOUT")
  • public class Checkout
  • private static long CHECKOUT_DAYS
    100060602414
  • _at_Id _at_GeneratedValue _at_Column(name"CHECKOUT_ID"
    )
  • private long id
  • _at_ManyToOne(optionalfalse)
  • _at_JoinColumn(name"CHECKOUT_BID")
  • private Borrower borrower

Inverse-side of relationship defines remote
property that defines the database mapping
Owning side uses a JoinColumn to name the
foreign key column for the relationship
35
_at_OneToMany Annotation
  • public interface OneToMany extends ...
  • Class targetEntity() default void.class
  • defines mapped type of related object
  • provider can determine value from property type
  • CascadeType cascade() default
  • defines which persistence operations propagate to
    related object
  • FetchType fetch() default EAGER
  • hint to provider whether related object is always
    necessary
  • String mappedBy() default
  • names property in related object that defines
    mapping to database

36
ManyToOne Bi-directional Example Usage
  • //get a borrower
  • ejava.examples.orm.rel.annotated.Borrower
    borrower
  • em.find(Borrower.class, borrowerId)
  • assertNotNull(borrower)
  • assertTrue(borrower.getCheckouts().size() 0)
  • //create 1st checkout
  • ejava.examples.orm.rel.annotated.Checkout
    checkout
  • new Checkout(new Date())
  • checkout.setBorrower(borrower) //set owning side
  • borrower.addCheckout(checkout) //set inverse
    side
  • //above is a wrapper around
  • // borrower.getCheckouts().add(checkout)
  • em.persist(checkout) //persist owning side of
    the relation

37
ManyToOne Bi-directional Example Usage (cont.)
  • //create a couple more
  • for(int i0 ilt5 i)
  • Checkout co new Checkout(new Date())
  • co.setBorrower(borrower) //set owning side
  • borrower.addCheckout(co) //set inverse
    side
  • //above is a wrapper around
  • // borrower.getCheckouts().add(checkout)
  • em.persist(co) //persist owning side of the
    relation
  • log.info("done populating borrower")
  • em.flush()
  • em.clear()
  • Borrower borrower2 em.find(Borrower.class,
    borrower.getId())
  • assertEquals(6, borrower2.getCheckouts().size())

38
Changing a Collection
  • Wrong!
  • don't replace the collection from the managed
    object with a transient one
  • CollectionltCheckoutgt newCheckouts ...
  • borrower.setCheckouts(newCheckouts)
    //WRONG!
  • Correct!
  • update the existing collection within the managed
    object
  • CollectionltCheckoutgt newCheckouts ...
  • borrower.getCheckouts().addAll(newCheckouts)

39
OneToMany
  • Uni-directional

40
OneToMany
  • Uni-directional
  • One side (owner) is only class that knows of
    relationship
  • uses _at_OneToMany annotation
  • This class defines mapping to database using a
    Join (or link) table
  • must use a _at_JoinTable
  • Bi-directional
  • same as ManyToOne bi-directional

41
Link/Join Table
42
OneToMany Uni-directional Example DB Schema
  • create table ORMREL_INVENTORY (id bigint
    generated by default as identity, name
    varchar(255), primary key (id))
  • create table ORMREL_INVENTORY_MEDIA
    (ORMREL_INVENTORY_id bigint not null,
    media_MEDIA_ID bigint not null, unique
    (media_MEDIA_ID))
  • create table ORMREL_MEDIA (MEDIA_ID bigint
    generated by default as identity, title
    varchar(255), primary key (MEDIA_ID))
  • alter table ORMREL_INVENTORY_MEDIA add constraint
    FKF6FA5C317DD5E49D foreign key (ORMREL_INVENTORY_i
    d) references ORMREL_INVENTORY
  • alter table ORMREL_INVENTORY_MEDIA add constraint
    FKF6FA5C31A70D4E48 foreign key (media_MEDIA_ID)
    references ORMREL_MEDIA

Link table declares foreign keys to form
relationships
Unique media ID guards against a single media
being mapped to multiple inventories
43
OneToMany Uni-directional Example Java Mapping
Inverse-side of relationship defines nothing
for uni-directional relationships
  • _at_Entity _at_Table(name"ORMREL_MEDIA")
  • public class Media
  • _at_Id _at_GeneratedValue _at_Column(name"MEDIA_ID")
  • private long id
  • _at_Entity _at_Table(name"ORMREL_INVENTORY")
  • public class Inventory
  • private long id
  • private String name
  • private CollectionltMediagt media new
    ArrayListltMediagt()
  • _at_OneToMany(cascadeCascadeType.ALL)
  • _at_JoinTable(name"ORMREL_INVENTORY_MEDIA")
  • public CollectionltMediagt getMedia()
  • return media
  • public void setMedia(CollectionltMediagt media)
  • this.media media

Owning side of OneToManyuni-directional must
define a link table to hold relationship
44
_at_JoinTable Annotation
  • public interface JoinTable extends ...
  • very similar to _at_Table annotation
  • String name() default
  • table name for join table
  • String catalog() default
  • catalog name for join table
  • String schema() default
  • schema name for join table
  • JoinColumn joinColumns() default
  • array of columns defining foreign key to this
    object
  • JoinColumn inverseJoinColumns() default
  • array of columns defining foreign key to related
    object
  • UniqueConstraint uniqueConstraints()

45
OneToMany Uni-directional Example Usage
  • //create owning side
  • ejava.examples.orm.rel.annotated.Inventory
    inventory1
  • new Inventory()
  • inventory1.setName("testLinkFind")
  • em.persist(inventory1)
  • //create and relate inverse side
  • for(int i0 ilt5 i)
  • ejava.examples.orm.rel.annotated.Media media
    new Media()
  • em.persist(media)
  • log.info("created media" media)
  • //relation defined to cascade perists
  • inventory1.getMedia().add(media)

46
OneToMany Uni-directional Example Usage (cont.)
  • em.getTransaction().commit()
  • em.clear()
  • em.getTransaction().begin()
  • //get new copy of inventory from DB
  • assertFalse("inventory still managed",em.contains(
    inventory1))
  • Inventory inventory2 em.find(Inventory.class,
    inventory1.getId())
  • assertNotNull("inventory not found", inventory2)
  • assertNotSame(inventory1, inventory2)
  • assertNotNull("media null", inventory2.getMedia())
  • assertEquals("unexpected media count"
    inventory2.getMedia().size(),
  • inventory1.getMedia().size(),
    inventory2.getMedia().size())

47
Using FK in uni-directional OneToMany
  • create table ORMO2M_CHILD (
  • CHILDID bigint generated by default as
    identity (start with 1),
  • name varchar(255),
  • PARENT_ID bigint,
  • primary key (CHILDID)
  • )
  • create table ORMO2M_PARENT (
  • PARENTID bigint generated by default as
    identity (start with 1),
  • name varchar(255),
  • primary key (PARENTID)
  • )
  • alter table ORMO2M_CHILD
  • add constraint FK257187DDF37CA975
  • foreign key (PARENT_ID)
  • references ORMO2M_PARENT

48
Using FK in uni-directional OneToMany
  • _at_Entity(name"O2MChild") _at_Table(name"ORMO2M_CHILD
    ")
  • public class OneManyChild
  • _at_Id _at_GeneratedValue _at_Column(name"CHILDID")
  • public long getId()
  • return id
  • _at_Entity(name"O2MOwningParent")
    _at_Table(name"ORMO2M_PARENT")
  • public class OneManyOwningParent
  • _at_Id _at_GeneratedValue _at_Column(name"PARENTID")
  • public long getId()
  • return id
  • _at_OneToMany
  • _at_JoinColumn(name"PARENT_ID")
  • //_at_JoinTable(
  • // joinColumns_at_JoinColumn(name"PARENT
    _ID"))

49
OneToMany bi-directional
  • The same as ManyToOne bi-directional
  • Spec requires _at_ManyToOne side of a bi-directional
    relationship be the owner

50
ManyToMany
  • Uni-directional
  • Bi-Directional

51
ManyToMany
  • Uni-directional
  • One class (owner) knows about relationship
  • uses _at_ManyToMany annotation
  • Owner defines mapping to database using a Join
    (or link) table
  • uses _at_JoinTable
  • Bi-directional
  • Both classes know of relationship
  • use _at_ManyToMany annotation
  • Owning side defines mapping to database
  • uses _at_JoinTable
  • Invserse side names property on remote end that
    defines mapping
  • uses _at_ManyToMany(mappedByremote property)

52
ManyToMany Uni-directional Example DB Schema
  • create table ORMREL_WANTED (id bigint generated
    by default as identity, primary key (id))
  • create table ORMREL_WANTED_MEDIA
    (ORMREL_WANTED_id bigint not null,
    media_MEDIA_ID bigint not null)
  • create table ORMREL_MEDIA (MEDIA_ID bigint
    generated by default as identity (start with 1),
    title varchar(255), primary key (MEDIA_ID))
  • alter table ORMREL_WANTED_MEDIA add constraint
    FKEE528304A70D4E48 foreign key (media_MEDIA_ID)
    references ORMREL_MEDIA
  • alter table ORMREL_WANTED_MEDIA add constraint
    FKEE52830486AFC6B6 foreign key (ORMREL_WANTED_id)
    references ORMREL_WANTED

Link table declares foreign keys to form
relationships
No unique ID guards for many to many mapping
53
ManyToMany Uni-directional Example Java Mapping
Inverse-side of relationship defines nothing
for uni-directional relationships
  • _at_Entity _at_Table(name"ORMREL_MEDIA")
  • public class Media
  • _at_Id _at_GeneratedValue _at_Column(name"MEDIA_ID")
  • private long id
  • _at_Entity _at_Table(name"ORMREL_WANTED")
  • public class WantList
  • private long id
  • private CollectionltMediagt media new
    ArrayListltMediagt()
  • _at_Id _at_GeneratedValue
  • public long getId() return id
  • public void setId(long id) this.id id
  • _at_ManyToMany
  • _at_JoinTable(name"ORMREL_WANTED_MEDIA")
    public CollectionltMediagt getMedia() return
    media
  • public void setMedia(CollectionltMediagt
    media)
  • this.media media

Owning side of ManyToManyuni-directional must
define a link table to hold relationship
54
_at_ManyToMany Annotation
  • public interface OneToMany extends ...
  • identical properties as OneToMany
  • Class targetEntity() default void.class
  • defines mapped type of related object
  • provider can determine value from property type
  • CascadeType cascade() default
  • defines which persistence operations propagate to
    related object
  • FetchType fetch() default EAGER
  • hint to provider whether related object is always
    necessary
  • String mappedBy() default
  • names property in related object that defines
    mapping to database

55
ManyToMany Uni-directional Example Usage
  • CollectionltWantListgt wantLists new
    ArrayListltWantListgt()
  • CollectionltMediagt media new ArrayListltMediagt()
  • //create owning side objects
  • for(int i0 ilt3 i)
  • ejava.examples.orm.rel.annotated.WantList
    wanted
  • new WantList()
  • em.persist(wanted)
  • wantLists.add(wanted)
  • //create inverse side objects
  • for (int i0 ilt2 i)
  • ejava.examples.orm.rel.annotated.Media
    mediaItem
  • new Media()
  • mediaItem.setTitle("title " i)
  • em.persist(mediaItem) //rel not defined to
    cascade
  • media.add(mediaItem)

56
ManyToMany Uni-directional Example Usage (cont.)
  • //relate the inverse-side objects to owning
    objects
  • for(WantList w wantLists)
  • for(Media m media)
  • //we can only navigate this in one
    direction
  • w.getMedia().add(m)
  • em.getTransaction().commit()
  • em.clear()

57
ManyToMany Uni-directional Example Usage (cont.)
  • //verify we don't have them in the cache
  • for (WantList w wantLists)
  • assertFalse("want list still managed",
    em.contains(w))
  • for (Media m media)
  • assertFalse("media still managed",
    em.contains(m))
  • for (WantList w wantLists)
  • WantList wanted em.find(WantList.class,
    w.getId())
  • assertNotNull("want list not found"
    w.getId(), wanted)
  • assertEquals("unepxected number of media",
  • wanted.getMedia().size(),
    media.size())

58
ManyToMany Bi-directional Example DB Schema
  • create table ORMREL_AUTHOR (id bigint generated
    by default as identity, name varchar(255),
    primary key (id))
  • create table ORMREL_AUTHOR_MEDIA (LINK_AUTHOR_ID
    bigint not null, LINK_MEDIA_ID bigint not null)
  • create table ORMREL_MEDIA (MEDIA_ID bigint
    generated by default as identity, title
    varchar(255), primary key (MEDIA_ID))
  • alter table ORMREL_AUTHOR_MEDIA add constraint
    FKA0D2B4E09B01C6F2 foreign key (LINK_MEDIA_ID)
    references ORMREL_MEDIA
  • alter table ORMREL_AUTHOR_MEDIA add constraint
    FKA0D2B4E089FFE922 foreign key (LINK_AUTHOR_ID)
    references ORMREL_AUTHOR

Link table declares foreign keys to form
relationships
No unique ID guards for many to many mapping
59
ManyToMany Bi-directional Example Java Mapping
Inverse-side of relationship defines property
on remote end that defines relationship
  • _at_Entity _at_Table(name"ORMREL_MEDIA")
  • public class Media
  • _at_ManyToMany(mappedBy"media")
  • private CollectionltAuthorgt authors new
    ArrayListltAuthorgt()
  • _at_Entity _at_Table(name"ORMREL_AUTHOR")
  • public class Author
  • private ListltMediagt media new
    ArrayListltMediagt()
  • _at_ManyToMany
  • _at_JoinTable(name"ORMREL_AUTHOR_MEDIA",
    joinColumns _at_JoinColumn(n
    ame"LINK_AUTHOR_ID"),
    inverseJoinColumns _at_JoinColumn(name"LINK_MED
    IA_ID"))
  • _at_OrderBy("title DESC")
  • public ListltMediagt getMedia() return media
  • public void setMedia(ListltMediagt media)
    this.mediamedia

Owning side of ManyToManybi-directional must
define a link table to hold relationship
60
ManyToMany Bi-directional Example Usage
  • CollectionltAuthorgt authors new
    ArrayListltAuthorgt()
  • CollectionltMediagt media new ArrayListltMediagt()
  • for(int i0 ilt5 i)
  • ...
  • em.persist(author)
  • authors.add(author)
  • for (int i0 ilt3 i)
  • ...
  • em.persist(mediaItem)
  • media.add(mediaItem)
  • for(Author a authors)
  • for(Media m media)
  • a.getMedia().add(m)
  • m.getAuthors().add(a)

set both sides of a bi-directional relationship
61
Map-based Collection
62
Map-based Collection Example DB Schema
  • create table ORMREL_LIBRARY (id bigint generated
    by default as identity, primary key (id))
  • create table ORMREL_LIBRARY_ORMREL_BORROWER
    (ORMREL_LIBRARY_id bigint not null,
    borrowers_BORROWER_ID bigint not null, primary
    key (ORMREL_LIBRARY_id, borrowers_BORROWER_ID),
    unique (borrowers_BORROWER_ID))
  • create table ORMREL_BORROWER (BORROWER_ID bigint
    not null, startDate date, endDate date,
    primary key (BORROWER_ID))
  • alter table ORMREL_LIBRARY_ORMREL_BORROWER add
    constraint FKE21AB3BE9B36B899 foreign key
    (borrowers_BORROWER_ID) references
    ORMREL_BORROWER
  • alter table ORMREL_LIBRARY_ORMREL_BORROWER add
    constraint FKE21AB3BE7A0BF0FD foreign key
    (ORMREL_LIBRARY_id) references ORMREL_LIBRARY

Link Table declares foreign keys to form
relationships
63
Map-based Collection Example Java Mapping
  • _at_Entity _at_Table(name"ORMREL_LIBRARY")
  • public class Library
  • private long id
  • private MapltLong, Borrowergt borrowers
  • new HashMapltLong, Borrowergt()
  • _at_OneToMany(cascadeCascadeType.ALL,
    fetchFetchType.LAZY)
  • _at_MapKey(name"id")
  • public MapltLong, Borrowergt getBorrowers()
  • return borrowers
  • public void setBorrowers(MapltLong, Borrowergt
    borrowers)
  • this.borrowers borrowers

MapKey defines property from related object to be
used as key in Map
64
Map-based Collection Example Usage
  • ejava.examples.orm.rel.annotated.Library library
  • new Library()
  • em.persist(library)
  • for(int i0 ilt5 i)
  • ejava.examples.orm.rel.annotated.Person
    person
  • new Person()
  • person.setFirstName("test")
  • person.setLastName("MapCreate-" i)
  • em.persist(person) //persist now - borrower
    copies id
  • ejava.examples.orm.rel.annotated.Borrower
    borrower
  • new Borrower(person)
  • library.getBorrowers().put(borrower.getId(),
    borrower)

65
CascadeType
  • ALL
  • combination of all types
  • PERSIST
  • related objects are automatically managed and
    will be persisted to the database when related to
    this object
  • REMOVE
  • related objects are deleted from database when
    this object is removed
  • REFRESH
  • related objects will have their states pulled
    from the database along with this object when it
    is refreshed
  • MERGE
  • related objects will have their states written to
    the database along with this object when it is
    merged

66
Summary
  • Relationship Sides
  • owning side
  • inverse side
  • Relationship Types
  • OneToOne
  • uni-directional, bi-directional
  • ManyToOne
  • uni-directional, bi-directional
  • OneToMany
  • uni-directional (bi-directional same as
    ManyToOne)
  • ManyToMany
  • uni-directional, bi-directional

67
Summary (cont.)
  • Collection Types
  • Collection, Set, List, Map
  • FetchType
  • EAGER
  • LAZY
  • CascadeType
  • ALL, PERSIST, REMOVE, MERGE, REFRESH

68
References
  • Enterprise JavaBeans 3.0, 5th Edition Burke
    Monsen-Haefel ISBN 0-596-00978-X O'Reilly
Write a Comment
User Comments (0)
About PowerShow.com