Professional Documents
Culture Documents
Entity Relationships
&KDSWHU FRYHUHG EDVLF SHUVLVWHQFH PDSSLQJV LQFOXGLQJ YDULRXV ZD\V WR GHILQH SUL
PDU\ NH\V DV ZHOO DV VLPSOH DQG FRPSOH[ SURSHUW\ W\SH PDSSLQJV 7KLV FKDSWHU UHWRROV
RXU HPSOR\HH UHJLVWU\ D ELW IXUWKHU E\ GLVFXVVLQJ WKH UHODWLRQVKLSV EHWZHHQ HQWLWLHV
,Q RUGHU WR PRGHO UHDO ZRUOG EXVLQHVV FRQFHSWV HQWLW\ EHDQV PXVW EH FDSDEOH RI IRUPLQJ
UHODWLRQVKLSV )RU LQVWDQFH DQ HPSOR\HH PD\ KDYH DQ DGGUHVV ZH¦G OLNH WR IRUP DQ
DVVRFLDWLRQ EHWZHHQ WKH WZR LQ RXU GDWDEDVH PRGHO 7KH DGGUHVV FRXOG EH TXHULHG DQG
FDFKHG OLNH DQ\ RWKHU HQWLW\ \HW D FORVH UHODWLRQVKLS ZRXOG EH IRUJHG ZLWK WKH
Employee HQWLW\ (QWLW\ EHDQV FDQ DOVR KDYH RQH WR PDQ\ PDQ\ WR RQH DQG PDQ\ WR
PDQ\ UHODWLRQVKLSV )RU H[DPSOH WKH Employee HQWLW\ PD\ KDYH PDQ\ SKRQH QXPEHUV
EXW HDFK SKRQH QXPEHU EHORQJV WR RQO\ RQH HPSOR\HH D RQH WR PDQ\ UHODWLRQVKLS
6LPLODUO\ DQ HPSOR\HH PD\ EHORQJ WR PDQ\ WHDPV ZLWKLQ KLV RU KHU RUJDQL]DWLRQ DQG
WHDPV PD\ KDYH DQ\ QXPEHU RI HPSOR\HHV D PDQ\ WR PDQ\ UHODWLRQVKLS
171
FRPSXWHU LV LQ WKH WHFK GHSDUWPHQW IRU VHUYLFLQJ LW¦V DOVR KHOSIXO WR ORFDWH WKH
HPSOR\HH ZKHQ DOO ZRUN LV FRPSOHWHG
2QH WR PDQ\ XQLGLUHFWLRQDO
7KH UHODWLRQVKLS EHWZHHQ DQ HPSOR\HH DQG D SKRQH QXPEHU $Q HPSOR\HH FDQ
KDYH PDQ\ SKRQH QXPEHUV EXVLQHVV KRPH FHOO HWF <RX PLJKW QHHG WR ORRN XS
DQ HPSOR\HH¦V SKRQH QXPEHU EXW \RX SUREDEO\ ZRXOGQ¦W XVH RQH RI WKRVH QXP
EHUV WR ORRN XS WKH HPSOR\HH
2QH WR PDQ\ ELGLUHFWLRQDO
7KH UHODWLRQVKLS EHWZHHQ DQ HPSOR\HH PDQDJHU DQG GLUHFW UHSRUWV *LYHQ D PDQ
DJHU ZH¦G OLNH WR NQRZ ZKR¦V ZRUNLQJ XQGHU KLP RU KHU 6LPLODUO\ ZH¦G OLNH WR EH
DEOH WR ILQG WKH PDQDJHU IRU D JLYHQ HPSOR\HH 1RWH WKDW D PDQ\ WR RQH ELGLUHF
WLRQDO UHODWLRQVKLS LV MXVW DQRWKHU SHUVSHFWLYH RQ WKH VDPH FRQFHSW
0DQ\ WR RQH XQLGLUHFWLRQDO
7KH UHODWLRQVKLS EHWZHHQ D FXVWRPHU DQG KLV RU KHU SULPDU\ HPSOR\HH FRQWDFW
*LYHQ D FXVWRPHU ZH¦G OLNH WR NQRZ ZKR¦V LQ FKDUJH RI KDQGOLQJ WKH DFFRXQW ,W
PLJKW EH OHVV XVHIXO WR ORRN XS DOO WKH DFFRXQWV D VSHFLILF HPSOR\HH LV IURQWLQJ
DOWKRXJK LI \RX ZDQW WKLV FDSDELOLW\ \RX FDQ LPSOHPHQW D PDQ\ WR RQH ELGLUHFWLRQDO
UHODWLRQVKLS
0DQ\ WR PDQ\ XQLGLUHFWLRQDO
7KH UHODWLRQVKLS EHWZHHQ HPSOR\HHV DQG WDVNV WR EH FRPSOHWHG (DFK WDVN PD\ EH
DVVLJQHG WR D QXPEHU RI HPSOR\HHV DQG HPSOR\HHV PD\ EH UHVSRQVLEOH IRU PDQ\
WDVNV )RU QRZ ZH¦OO DVVXPH WKDW JLYHQ D WDVN ZH QHHG WR ILQG LWV UHODWHG HPSOR\HHV
EXW QRW WKH RWKHU ZD\ DURXQG ,I \RX WKLQN \RX QHHG WR GR VR LPSOHPHQW LW DV D
ELGLUHFWLRQDO UHODWLRQVKLS
0DQ\ WR PDQ\ ELGLUHFWLRQDO
7KH UHODWLRQVKLS EHWZHHQ DQ HPSOR\HH DQG WKH WHDPV WR ZKLFK KH RU VKH EHORQJV
7HDPV PD\ DOVR KDYH PDQ\ HPSOR\HHV DQG ZH¦G OLNH WR GR ORRNXSV LQ ERWK
GLUHFWLRQV
1RWH WKDW WKHVH UHODWLRQV UHSUHVHQW WKH QDYLJDELOLW\ RI \RXU GRPDLQ PRGHO 8VLQJ -3$
4/ RU WKH &ULWHULD $3, FRYHUHG LQ &KDSWHU \RX¦OO EH DEOH WR UHWXUQ HYHQ DQ XQ
PDSSHG DVVRFLDWLRQ IRU H[DPSOH UHWXUQ WKH WDVNV IRU D JLYHQ HPSOR\HH HYHQ LI WKH
DVVRFLDWLRQ KDV EHHQ PDSSHG DV PDQ\ WR RQH XQLGLUHFWLRQDO 2QFH DJDLQ WKH DVVRFL
DWLRQV GHILQHG LQ WKH PHWDGDWD UHSUHVHQW WKH GRPDLQ REMHFW QDYLJDWLRQ RQO\
,Q WKLV FKDSWHU ZH GLVFXVV KRZ WR VSHFLI\ UHODWLRQVKLSV E\ DSSO\LQJ DQQRWDWLRQV WR \RXU
UHODWHG HQWLW\ EHDQV :H DOVR GLVFXVV VHYHUDO GLIIHUHQW FRPPRQ GDWDEDVH VFKHPDV DQG
\RX ZLOO OHDUQ KRZ WR PDS WKHP WR \RXU DQQRWDWHG UHODWLRQVKLSV
Programming model
,Q XQLGLUHFWLRQDO UHODWLRQVKLSV QDYLJDWHG RQO\ RQH ZD\ RQH RI WKH HQWLW\ EHDQV GHILQHV
D SURSHUW\ WKDW OHWV LW JHW RU VHW WKH RWKHU EHDQ LQ WKH UHODWLRQVKLS 7KXV LQVLGH WKH
Employee FODVV \RX FDQ FDOO WKH getAddress() setAddress() PHWKRGV WR DFFHVV WKH $G
GUHVV HQWLW\ EXW WKHUH DUH QR PHWKRGV LQVLGH WKH Address FODVV WR DFFHVV WKH Employee
/HW¦V ORRN DW KRZ ZH ZRXOG PDUN XS WKH Employee EHDQ FODVV WR LPSOHPHQW WKLV RQH WR
RQH UHODWLRQVKLS WR Address
/**
* The employee's address
*/
@OneToOne
@JoinColumn(name="ADDRESS_ID")
// Unidirectional relationship
private Address address;
@Target({METHOD, FIELD})
@Retention(RUNTIME)
public @interface JoinColumn
{
String name() default "";
String referencedColumnName() default "";
boolean unique() default false;
boolean nullable() default true;
boolean insertable() default true;
boolean updatable() default true;
String columnDefinition() default "";
String table() default "";
}
@Target({METHOD, FIELD})
@Retention(RUNTIME)
public @interface OneToOne
{
Class targetEntity() default void.class;
CascadeType[] cascade() default {};
FetchType fetch() default EAGER;
boolean optional() default true;
String mappedBy() default "";
boolean orphanRemoval() default false;
}
7KH targetEntity() DWWULEXWH UHSUHVHQWV WKH HQWLW\ FODVV \RX KDYH D UHODWLRQVKLS WR
8VXDOO\ \RX GR QRW KDYH WR LQLWLDOL]H WKLV DWWULEXWH DV WKH SHUVLVWHQFH SURYLGHU FDQ
ILJXUH RXW WKH UHODWLRQVKLS \RX DUH VHWWLQJ XS IURP WKH SURSHUW\¦V W\SH
7KH name() DWWULEXWH UHIHUV WR WKH SULPDU\ NH\ FROXPQ QDPH RI WKH HQWLW\ WKH DQQRWDWLRQ
LV DSSOLHG WR 8QOHVV \RXU HQWLW\ KDV D FRPSRVLWH SULPDU\ NH\ \RX FDQ OHDYH WKLV EODQN
DQG WKH SHUVLVWHQFH SURYLGHU ZLOO ILJXUH LW RXW
7KH referencedColumnName() LV WKH FROXPQ WR MRLQ WR RQ WKH UHODWHG HQWLW\ ,I WKLV LV OHIW
EODQN LW LV DVVXPHG WKDW WKH UHODWHG HQWLW\¦V SULPDU\ NH\ ZLOO EH XVHG
7KH columnDefinition() LV XVHG ZKHQ WKH SHUVLVWHQFH SURYLGHU LV JHQHUDWLQJ VFKHPD
DQG LWV YDOXH ZLOO VSHFLI\ WKH 64/ W\SH RI WKH referencedColumnName()
,I WKH SULPDU\ NH\ MRLQ LQ TXHVWLRQ LV RI D FRPSRVLWH QDWXUH WKHQ WKH
@javax.persistence.PrimaryKeyJoinColumns DQQRWDWLRQ LV DYDLODEOH WR \RX
public @interface PrimaryKeyJoinColumns
{
PrimaryKeyJoinColumn[] value();
}
6LQFH ZH¦UH MRLQLQJ RQ WKH SULPDU\ NH\V RI WKH Employee DQG Address HQWLWLHV DQG WKH\
DUH QRW FRPSRVLWH NH\V ZH FDQ VLPSO\ DQQRWDWH WKH DGGUHVV SURSHUW\ RI Employee ZLWK
WKH GHIDXOWHG @PrimaryKeyJoinColumn DQQRWDWLRQ
:KHQ \RX GR QRW VSHFLI\ DQ\ GDWDEDVH PDSSLQJ IRU D XQLGLUHFWLRQDO RQH WR RQH
UHODWLRQVKLS WKH SHUVLVWHQFH SURYLGHU ZLOO JHQHUDWH WKH QHFHVVDU\ IRUHLJQ NH\ PDSSLQJV
IRU \RX ,Q RXU HPSOR\HH DGGUHVV UHODWLRQVKLS H[DPSOH WKH IROORZLQJ WDEOHV ZRXOG EH
JHQHUDWHG
CREATE TABLE "PUBLIC"."EMPLOYEE"
(
ID bigint PRIMARY KEY NOT NULL,
ADDRESS_ID bigint
)
;
)RU XQLGLUHFWLRQDO RQH WR RQH UHODWLRQVKLSV WKH GHIDXOW PDSSLQJ FUHDWHV D IRUHLJQ NH\
FROXPQ QDPHG IURP D FRPELQDWLRQ RI WKH SURSHUW\ \RX DUH PDSSLQJ IROORZHG E\
DQ _ XQGHUVFRUH FKDUDFWHU FRQFDWHQDWHG ZLWK WKH SULPDU\ NH\ FROXPQ QDPH RI WKH
UHIHUHQFHG WDEOH
2QH WR RQH ELGLUHFWLRQDO UHODWLRQVKLSV PD\ PRGHO UHODWLRQDO GDWDEDVH VFKHPDV LQ WKH
VDPH ZD\ DV RXU RQH WR RQH XQLGLUHFWLRQDO UHODWLRQVKLS LQ ZKLFK RQH RI WKH WDEOHV KROGV
D IRUHLJQ NH\ WKDW UHIHUHQFHV WKH RWKHU 5HPHPEHU WKDW LQ D UHODWLRQDO GDWDEDVH PRGHO
WKHUH LV QR VXFK QRWLRQ RI GLUHFWLRQDOLW\ VR WKH VDPH GDWDEDVH VFKHPD ZLOO EH XVHG IRU
ERWK XQLGLUHFWLRQDO DQG ELGLUHFWLRQDO REMHFW UHODWLRQVKLSV
7R PRGHO WKH UHODWLRQVKLS EHWZHHQ WKH Employee DQG Computer HQWLWLHV ZH QHHG WR GH
FODUH D UHODWLRQVKLS SURSHUW\ QDPHG owner LQ WKH Computer EHDQ FODVV
@Entity
public class Computer
{
...
@OneToOne
// Bidirectional relationship, mappedBy
// is declared on the non-owning side
private Employee owner;
...
}
7KH mappedBy() DWWULEXWH LV QHZ KHUH 7KLV DWWULEXWH VHWV XS WKH ELGLUHFWLRQDO UHODWLRQ
VKLS DQG WHOOV WKH SHUVLVWHQFH PDQDJHU WKDW WKH LQIRUPDWLRQ IRU PDSSLQJ WKLV UHODWLRQ
VKLS WR RXU WDEOHV LV VSHFLILHG LQ WKH Computer EHDQ FODVV VSHFLILFDOO\ WR WKH owner
SURSHUW\ RI Computer
:H KDYH WKH cascade() DWWULEXWH VHW WR HPSW\ VR ZH PXVW SHUIRUP WKH DVVRFLDWLRQ DIWHU
HDFK REMHFW LV SHUVLVWHG DQG WKHUHIRUH PDQDJHG :KHQ ZH GLVFXVV FDVFDGLQJ RSHUDWLRQV
\RX ZLOO VHH WKDW WKHUH DUH ZD\V WR SHUVLVW XQPDQDJHG REMHFWV DV SDUW RI DQ DVVRFLDWLRQ
DXWRPDWLFDOO\
7KHUH DUH VRPH SHFXOLDULWLHV ZLWK ELGLUHFWLRQDO UHODWLRQVKLSV :LWK DOO ELGLUHFWLRQDO
UHODWLRQVKLS W\SHV LQFOXGLQJ RQH WR RQH WKHUH LV DOZD\V WKH FRQFHSW RI DQ RZQLQJ VLGH
RI WKH UHODWLRQVKLS $OWKRXJK D setOwner() PHWKRG LV DYDLODEOH LQ WKH Computer EHDQ
FODVV LW ZLOO QRW FDXVH D FKDQJH LQ WKH SHUVLVWHQW UHODWLRQVKLS LI ZH VHW LW :KHQ ZH
PDUNHG WKH @OneToOne UHODWLRQVKLS LQ WKH Employee EHDQ FODVV ZLWK WKH mappedBy() DW
WULEXWH WKLV GHVLJQDWHG WKH Employee HQWLW\ DV WKH LQYHUVH VLGH RI WKH UHODWLRQVKLS 7KLV
PHDQV WKDW WKH Computer HQWLW\ LV WKH RZQLQJ VLGH RI WKH UHODWLRQVKLS
,I WKH HPSOR\HH EURNH KLV FRPSXWHU \RX ZRXOG KDYH WR VHW WKH UHODWLRQVKLS WR QXOO RQ
ERWK VLGHV DQG WKHQ UHPRYH WKH Computer HQWLW\ IURP WKH GDWDEDVH
2QH WR PDQ\ XQLGLUHFWLRQDO UHODWLRQVKLSV EHWZHHQ WKH EMPLOYEE DQG PHONE WDEOHV FRXOG
EH LPSOHPHQWHG LQ D YDULHW\ RI ZD\V )RU WKLV H[DPSOH ZH KDYH FKRVHQ WR LQWURGXFH D
QHZ WDEOH D MRLQ WDEOH WR PDS SKRQHV WR HPSOR\HHV
CREATE TABLE "PUBLIC"."EMPLOYEE_PHONE"
(
EMPLOYEE_ID bigint NOT NULL,
PHONES_ID bigint NOT NULL
)
;
ALTER TABLE "PUBLIC"."EMPLOYEE_PHONE"
ADD CONSTRAINT FK1E56289D581FE7C
FOREIGN KEY (PHONES_ID)
REFERENCES "PUBLIC"."PHONE"(PHONES_ID)
;
ALTER TABLE "PUBLIC"."EMPLOYEE_PHONE"
ADD CONSTRAINT FK1E56289DD9454221
FOREIGN KEY (EMPLOYEE_ID)
REFERENCES "PUBLIC"."EMPLOYEE"(EMPLOYEE_ID)
;
Programming model
<RX GHFODUH RQH WR PDQ\ UHODWLRQVKLSV XVLQJ WKH @javax.persistence.OneToMany
DQQRWDWLRQ
package javax.persistence;
@Target({METHOD, FIELD})
@Retention(RUNTIME)
public @interface OneToMany
{
Class targetEntity() default void.class;
CascadeType[] cascade() default {};
FetchType fetch() default LAZY;
String mappedBy() default "";
boolean orphanRemoval() default false;
}
7KH DWWULEXWH GHILQLWLRQV DUH SUHWW\ PXFK WKH VDPH DV WKRVH IRU WKH @OneToOne
DQQRWDWLRQ
,Q WKH SURJUDPPLQJ PRGHO ZH UHSUHVHQW PXOWLSOLFLW\ E\ GHILQLQJ D UHODWLRQVKLS SURS
HUW\ WKDW FDQ SRLQW WR PDQ\ HQWLW\ EHDQV DQG DQQRWDWLQJ LW ZLWK @OneToMany 7R KROG
WKLV W\SH RI GDWD ZH¦OO HPSOR\ VRPH GDWD VWUXFWXUHV IURP WKH java.util SDFNDJH
Collection List Map DQG Set 7KH Collection PDLQWDLQV D KRPRJHQHRXV JURXS RI
HQWLW\ REMHFW UHIHUHQFHV ZKLFK PHDQV WKDW LW FRQWDLQV PDQ\ UHIHUHQFHV WR RQH NLQG RI
HQWLW\ EHDQ 7KH Collection W\SH PD\ FRQWDLQ GXSOLFDWH UHIHUHQFHV WR WKH VDPH HQWLW\
EHDQ DQG WKH Set W\SH PD\ QRW
7R LOOXVWUDWH KRZ DQ HQWLW\ EHDQ XVHV D FROOHFWLRQ EDVHG UHODWLRQVKLS OHW¦V ORRN DW VRPH
FRGH WKDW LQWHUDFWV ZLWK WKH EntityManager
// Create an Employee
final Employee jaikiranPai = new Employee("Jaikiran Pai");
// Persist
final EntityManager em = null; // Assume we have this
em.persist(jaikiranPai);
em.persist(phone1);
em.persist(phone2);
,I \RX QHHG WR UHPRYH D Phone IURP WKH UHODWLRQVKLS \RX QHHG WR UHPRYH WKH Phone IURP
ERWK WKH FROOHFWLRQ DQG WKH GDWDEDVH
jaikiranPai.getPhones().remove(phone1);
em.remove(phone1);
5HPRYLQJ WKH Phone IURP WKH Employee¦V FROOHFWLRQ GRHV QRW UHPRYH WKH Phone IURP WKH
GDWDEDVH <RX KDYH WR GHOHWH WKH Phone H[SOLFLWO\ RWKHUZLVH LW ZLOO EH RUSKDQHG 7KH
orphanRemoval DWWULEXWH RI @OneToMany PD\ UHPRYH WKH RUSKDQHG SKRQH DXWRPDWLFDOO\
LI VHW WR true
Programming model
0DQ\ WR RQH UHODWLRQVKLSV DUH GHVFULEHG ZLWK WKH @javax.persistence.ManyToOne
DQQRWDWLRQ
public @interface ManyToOne
{
Class targetEntity() default void.class;
CascadeType[] cascade() default {};
FetchType fetch() default EAGER;
7KH DWWULEXWH GHILQLWLRQV DUH SUHWW\ PXFK WKH VDPH DV WKRVH IRU WKH @OneToOne
DQQRWDWLRQ
7KH SURJUDPPLQJ PRGHO LV TXLWH VLPSOH IRU RXU UHODWLRQVKLS :H DGG D
primaryContact SURSHUW\ WR RXU Customer HQWLW\ EHDQ FODVV DQG DQQRWDWH LW ZLWK WKH
@ManyToOne DQQRWDWLRQ
@Entity
public class Customer
{
...
/**
* The primary {@link Employee} contact for this {@link Customer}
*/
@ManyToOne
// Unidirectional
private Employee primaryContact;
...
}
7KH UHODWLRQVKLS EHWZHHQ WKH Employee DQG Customer HQWLWLHV LV XQLGLUHFWLRQDO VR WKH
Employee EHDQ FODVV GRHVQ¦W GHILQH DQ\ UHODWLRQVKLS EDFN WR WKH Customer
$OO RI WKLV VKRXOG EH PXQGDQH WR \RX QRZ 7KH LPSDFW RI H[FKDQJLQJ Employee UHIHU
HQFHV EHWZHHQ Customer HQWLWLHV ZRUNV MXVW DV ZH¦YH VHHQ ZLWK WKH SUHYLRXV UHODWLRQVKLS
W\SHV
Programming model
%HFDXVH WKLV LV D ELGLUHFWLRQDO UHODWLRQVKLS WKH PDQDJHU NQRZV KLV RU KHU UHSRUWV DQG
DOVR KLV RU KHU RZQ PDQDJHU 7KH Employee FODVV PD\ WKHUHIRUH FRQWDLQ
/**
* Manager of the {@link Employee}
*/
@ManyToOne
private Employee manager;
/**
* {@link Employee}s reporting to this {@link Employee}
*/
@OneToMany(mappedBy = "manager")
private Collection<Employee> peons;
7KH HQWLUH UHODWLRQVKLS KHUH LV FRQWDLQHG ZLWKLQ WKH Employee FODVV $V ZLWK DOO
ELGLUHFWLRQDO UHODWLRQVKLSV WKH LQYHUVH VLGH VSHFLILHV mappedBy WR LQGLFDWH WKH SURSHUW\
WR DFW DV WKH RZQLQJ VLGH
-DYD 3HUVLVWHQFH FXUUHQWO\ UHTXLUHV WKDW WKH PDQ\ WR RQH VLGH DOZD\V EH WKH RZQHU 7KLV
PD\ VHHP YHU\ FRQIXVLQJ EXW LI \RX REH\ WKH FDUGLQDO UXOH RI DOZD\V ZLULQJ ERWK VLGHV
RI D UHODWLRQVKLS WKHQ \RX ZLOO KDYH QR SUREOHPV
Usage
&OLHQW XVDJH LV DV ZH¦YH VHHQ EHIRUH
// Create a few Employees
final Employee alrubinger = new Employee("Andrew Lee Rubinger");
final Employee carloDeWolf = new Employee("Carlo de Wolf - SuperLead!");
final Employee jaikiranPai = new Employee("Jaikiran Pai");
final Employee bigD = new Employee("Big D");
// Persist
em.persist(jaikiranPai);
$JDLQ ZH XVH D MRLQ WDEOH WR HVWDEOLVK D PDQ\ WR PDQ\ ELGLUHFWLRQDO UHODWLRQVKLS DQG
ZH¦OO FDOO WKLV WKH TEAM_EMPLOYEE WDEOH +HUH ZH PDLQWDLQ WZR IRUHLJQ NH\ FROXPQV¢
RQH IRU WKH EMPLOYEE WDEOH DQG DQRWKHU IRU WKH TEAM WDEOH
CREATE TABLE "PUBLIC"."TEAM_EMPLOYEE"
(
TEAMS_ID bigint NOT NULL,
MEMBERS_ID bigint NOT NULL
)
;
ALTER TABLE "PUBLIC"."TEAM_EMPLOYEE"
ADD CONSTRAINT FKA63C2502B25E948
FOREIGN KEY (TEAMS_ID)
REFERENCES "PUBLIC"."TEAM"(TEAMS_ID)
Programming model
0DQ\ WR PDQ\ UHODWLRQVKLSV DUH ORJLFDOO\ GHILQHG XVLQJ WKH @javax.persistence.Many
ToMany DQQRWDWLRQ
public @interface ManyToMany
{
Class targetEntity( ) default void.class;
CascadeType[] cascade( ) default {};
FetchType fetch( ) default LAZY;
String mappedBy( ) default "";
}
7R PRGHO WKH PDQ\ WR PDQ\ ELGLUHFWLRQDO UHODWLRQVKLS EHWZHHQ WKH Employee DQG
Team HQWLWLHV ZH QHHG WR LQFOXGH FROOHFWLRQ EDVHG UHODWLRQVKLS SURSHUWLHV LQ ERWK EHDQ
FODVVHV
@Entity
public class Employee
{
...
/**
* The {@link Team}s to which this {@link Employee} belongs
*/
@ManyToMany(mappedBy = "members")
private Collection<Team> teams;
...
}
@Entity
public class Team
{
...
/**
* {@link Employee}s on this {@link Task}.
*/
@ManyToMany
private Collection<Employee> members;
...
}
// Get EM
final EntityManager em = null; // Assume we have this
// Persist
em.persist(pmuir);
em.persist(dallen);
em.persist(aslak);
em.persist(seam);
em.persist(arquillian);
7KLV PDQ\ WR PDQ\ XQLGLUHFWLRQDO UHODWLRQVKLS ORRNV D ORW OLNH WKH MRLQ WDEOH PDSSLQJ
IRU WKH PDQ\ WR PDQ\ ELGLUHFWLRQDO UHODWLRQVKLS GLVFXVVHG HDUOLHU 7KH ELJ GLIIHUHQFH LV
WKDW WKH REMHFW PRGHO ZLOO PDLQWDLQ D UHIHUHQFH RQO\ LQ RQH GLUHFWLRQ
Programming model
7R PRGHO WKLV UHODWLRQVKLS ZH QHHG WR DGG D FROOHFWLRQ EDVHG UHODWLRQVKLS ILHOG IRU
Employee EHDQV WR WKH Task
@Entity
public class Task
{
...
/**
* {@link Employee} in charge of this {@link Task}
%HFDXVH WKH UHODWLRQVKLS LV XQLGLUHFWLRQDO WKHUH DUH QR RZQLQJ RU LQYHUVH VLGHV DQG ZH
PD\ RPLW WKH mappedBy DWWULEXWH RI @ManyToMany
8VDJH LV VLPLODU WR ZKDW ZH¦YH DOUHDG\ VHHQ
// Create a couple of employees
final Employee smarlow = new Employee("Scott Marlow");
final Employee jpederse = new Employee("Jesper Pedersen");
// Persist
final EntityManager em = null; // Assume we have this
em.persist(smarlow);
em.persist(jpederse);
em.persist(task1);
em.persist(task2);
// Associate
task1.getOwners().add(smarlow);
task1.getOwners().add(jpederse);
task2.getOwners().add(smarlow);
task2.getOwners().add(jpederse);
7KH value() DWWULEXWH DOORZV \RX WR GHFODUH SDUWLDO -3$ 4/ WKDW VSHFLILHV KRZ \RX ZDQW
WKH UHODWLRQVKLS WR EH RUGHUHG ZKHQ LW LV IHWFKHG IURP WKH GDWDEDVH ,I WKH value()
DWWULEXWH LV OHIW HPSW\ WKH List LV VRUWHG LQ DVFHQGLQJ RUGHU EDVHG RQ WKH YDOXH RI WKH
SULPDU\ NH\
/HW¦V WDNH WKH Employee Team UHODWLRQVKLS ZKLFK LV D PDQ\ WR PDQ\ ELGLUHFWLRQDO UHOD
WLRQVKLS DQG KDYH WKH teams DWWULEXWH RI Employee UHWXUQ D List WKDW LV VRUWHG
DOSKDEHWLFDOO\ E\ WKH Team HQWLW\¦V QDPH
@Entity
public class Employee
{
...
@ManyToMany
@OrderBy("name ASC")
private List<Team> teams;
...
}
"name ASC" WHOOV WKH SHUVLVWHQFH SURYLGHU WR VRUW WKH Team¦V name LQ DVFHQGLQJ RUGHU <RX
FDQ XVH ASC IRU DVFHQGLQJ RUGHU DQG DESC IRU GHVFHQGLQJ RUGHU <RX FDQ DOVR VSHFLI\
DGGLWLRQDO UHVWULFWLRQV VXFK DV @OrderBy('name asc, otherattribute asc") ,Q WKLV
FDVH WKH OLVW ZLOO EH RUGHUHG E\ lastname DQG IRU GXSOLFDWH QDPHV LW ZLOO EH RUGHUHG
E\ WKH otherattribute
Map-Based Relationship
7KH java.util.Map LQWHUIDFH FDQ EH XVHG WR H[SUHVV FROOHFWLRQ EDVHG UHODWLRQVKLSV ,Q
WKLV FDVH WKH SHUVLVWHQFH SURYLGHU FUHDWHV D PDS ZLWK WKH NH\ EHLQJ D VSHFLILF SURSHUW\
RI WKH UHODWHG HQWLW\ DQG WKH YDOXH EHLQJ WKH HQWLW\ LWVHOI ,I \RX XVH D java.util.Map \RX
PXVW XVH WKH @javax.persistence.MapKey DQQRWDWLRQ
package javax.persistence;
7KH name() DWWULEXWH LV WKH QDPH RI WKH SHUVLVWHQW SURSHUW\ WKDW \RX ZDQW WR UHSUHVHQW
WKH NH\ ILHOG RI WKH PDS REMHFW ,I \RX OHDYH WKLV EODQN LW LV DVVXPHG \RX DUH XVLQJ WKH
SULPDU\ NH\ RI WKH UHODWHG HQWLW\ DV WKH NH\ RI WKH PDS
)RU DQ H[DPSOH OHW¦V XVH D PDS WR UHSUHVHQW WKH RQH WR PDQ\ XQLGLUHFWLRQDO Employee
Phone UHODWLRQVKLS GLVFXVVHG HDUOLHU LQ WKLV FKDSWHU
@Entity
public class Employee
,Q WKLV H[DPSOH WKH phones SURSHUW\ RI Employee ZLOO UHWXUQ D java.util.Map ZKHUH WKH
NH\ LV WKH number SURSHUW\ RI WKH Phone HQWLW\ DQG WKH YDOXH LV RI FRXUVH WKH Phone HQWLW\
LWVHOI 7KHUH LV QR H[WUD FROXPQ WR NHHS WKH PDS NH\ VLQFH WKH PDS NH\ LV ERUURZHG
IURP WKH Phone HQWLW\
,QYRNLQJ WKH size() PHWKRG RI WKH phones FROOHFWLRQ FDXVHV WKH UHODWLRQVKLS WR EH ORDGHG
IURP WKH GDWDEDVH ,W LV LPSRUWDQW WR QRWH WKDW WKLV OD]\ LQLWLDOL]DWLRQ GRHV QRW KDSSHQ
XQOHVV WKH HQWLW\ EHDQ LV EHLQJ PDQDJHG E\ D SHUVLVWHQFH FRQWH[W ,I WKH HQWLW\ EHDQ LV
GHWDFKHG WKH VSHFLILFDWLRQ LV QRW FOHDU RQ ZKDW DFWLRQV WKH SHUVLVWHQFH SURYLGHU VKRXOG
SHUIRUP ZKHQ DFFHVVLQJ DQ XQORDGHG UHODWLRQVKLS RI D GHWDFKHG HQWLW\ 0RVW SHUVLV
WHQFH SURYLGHUV WKURZ VRPH NLQG RI OD]\ LQVWDQWLDWLRQ H[FHSWLRQ ZKHQ \RX FDOO WKH
DFFHVVRU RI WKH UHODWLRQVKLS RU ZKHQ \RX WU\ WR LQYRNH DQ RSHUDWLRQ RQ WKH UHODWLRQVKLS
RI D GHWDFKHG HQWLW\
Employee employee = entityManager.find(Employee.class, id);
entityManager.detach(employee);
try
{
int numPhones = employee.getPhones().size();
}
catch (SomeVendorLazyInitializationException ex)
{
}
Cascading
7KHUH LV RQH DQQRWDWLRQ DWWULEXWH WKDW ZH KDYH LJQRUHG VR IDU WKH cascade() DWWULEXWH
RI WKH @OneToOne @OneToMany @ManyToOne DQG @ManyToMany UHODWLRQVKLS DQQRWDWLRQV
7KLV VHFWLRQ GLVFXVVHV LQ GHWDLO WKH EHKDYLRU WKDW LV DSSOLHG ZKHQ XVLQJ WKH cascade()
DWWULEXWH
:KHQ \RX SHUIRUP DQ HQWLW\ PDQDJHU RSHUDWLRQ RQ DQ HQWLW\ EHDQ LQVWDQFH \RX FDQ
DXWRPDWLFDOO\ KDYH WKH VDPH RSHUDWLRQ SHUIRUPHG RQ DQ\ UHODWLRQVKLS SURSHUWLHV WKH
HQWLW\ PD\ KDYH 7KLV LV FDOOHG FDVFDGLQJ )RU H[DPSOH LI \RX DUH SHUVLVWLQJ D QHZ
Employee HQWLW\ ZLWK D QHZ DGGUHVV DQG SKRQH QXPEHU DOO \RX KDYH WR GR LV ZLUH WKH
REMHFW DQG WKH HQWLW\ PDQDJHU FDQ DXWRPDWLFDOO\ FUHDWH WKH HPSOR\HH DQG LWV UHODWHG
HQWLWLHV DOO LQ RQH persist() PHWKRG FDOO
Employee employee = new Employee();
customer.setAddress(new Address());
customer.getPhoneNumbers().add(new Phone());
:LWK WKH -DYD 3HUVLVWHQFH VSHFLILFDWLRQ FDVFDGLQJ FDQ EH DSSOLHG WR D YDULHW\ RI HQWLW\
PDQDJHU RSHUDWLRQV LQFOXGLQJ persist() merge() remove() DQG refresh() 7KLV
Cascading | 191
IHDWXUH LV HQDEOHG E\ VHWWLQJ WKH javax.persistence.CascadeType RI WKH UHODWLRQVKLS
DQQRWDWLRQ¦V cascade() DWWULEXWH 7KH CascadeType LV GHILQHG DV D -DYD HQXPHUDWLRQ
public enum CascadeType
{
ALL, PERSIST,
MERGE, REMOVE,
REFRESH
}
7KH ALL YDOXH UHSUHVHQWV DOO RI WKH FDVFDGH RSHUDWLRQV 7KH UHPDLQLQJ YDOXHV UHSUHVHQW
LQGLYLGXDO FDVFDGH RSHUDWLRQV 7KH cascade() DWWULEXWH LV DQ DUUD\ RI WKH FDVFDGH RSHU
DWLRQV \RX ZDQW DSSOLHG WR \RXU UHODWHG HQWLWLHV
PERSIST
PERSIST KDV WR GHDO ZLWK WKH FUHDWLRQ RI HQWLWLHV ZLWKLQ WKH GDWDEDVH ,I ZH KDG D
CascadeType RI PERSIST RQ WKH Employee VLGH RI RXU RQH WR RQH UHODWLRQVKLS \RX ZRXOG
QRW KDYH WR SHUVLVW \RXU FUHDWHG Address DV ZHOO ,W ZRXOG EH FUHDWHG IRU \RX 7KH SHU
VLVWHQFH SURYLGHU DOVR ZLOO H[HFXWH WKH DSSURSULDWH 64/ INSERT VWDWHPHQWV LQ WKH DS
SURSULDWH RUGHU IRU \RX
,I \RX GLG QRW KDYH D FDVFDGH SROLF\ RI PERSIST WKHQ \RX ZRXOG KDYH WR FDOO
EntityManager.persist() RQ WKH DGGUHVV REMHFW DV ZHOO DV ZH GR LQ WKH H[DPSOH
MERGE
MERGE GHDOV ZLWK HQWLW\ V\QFKURQL]DWLRQ PHDQLQJ LQVHUWV DQG PRUH LPSRUWDQWO\ XS
GDWHV 7KHVH DUHQ¦W XSGDWHV LQ WKH WUDGLWLRQDO VHQVH ,I \RX UHPHPEHU IURP SUHYLRXV
FKDSWHUV ZH PHQWLRQHG WKDW REMHFWV FRXOG EH GHWDFKHG IURP SHUVLVWHQW PDQDJHPHQW
DQG VHULDOL]HG WR D UHPRWH FOLHQW XSGDWHV FRXOG EH SHUIRUPHG ORFDOO\ RQ WKDW UHPRWH
FOLHQW WKH REMHFW LQVWDQFH ZRXOG EH VHQW EDFN WR WKH VHUYHU DQG WKH FKDQJHV ZRXOG EH
PHUJHG EDFN LQWR WKH GDWDEDVH 0HUJLQJ LV DERXW V\QFKURQL]LQJ WKH VWDWH RI D GHWDFKHG
REMHFW LQVWDQFH EDFN WR SHUVLVWHQW VWRUDJH
6R EDFN WR ZKDW MERGE PHDQV MERGE LV VLPLODU WR PERSIST ,I \RX KDYH D FDVFDGH SROLF\
RI MERGE WKHQ \RX GR QRW KDYH WR FDOO EntityManager.merge() IRU WKH FRQWDLQHG UHODWHG
HQWLW\
employee.setName("William");
employee.getAddress().setCity("Boston");
entityManager.merge(employee);
,Q WKLV H[DPSOH ZKHQ WKH employee YDULDEOH LV PHUJHG E\ WKH HQWLW\ PDQDJHU WKH HQWLW\
PDQDJHU ZLOO FDVFDGH WKH PHUJH WR WKH FRQWDLQHG address SURSHUW\ DQG WKH city DOVR
ZLOO EH XSGDWHG LQ WKH GDWDEDVH
employee.getPhoneNumbers().add(phone);
entityManager.merge(employee);
,Q WKLV H[DPSOH ZH DOORFDWH D Phone DQG DGG LW WR DQ Employee¦V OLVW RI SKRQH QXPEHUV
:H WKHQ FDOO merge() ZLWK WKH HPSOR\HH DQG VLQFH ZH KDYH WKH MERGE CascadeType VHW
RQ WKLV UHODWLRQVKLS WKH SHUVLVWHQFH SURYLGHU ZLOO VHH WKDW LW LV D QHZ Phone HQWLW\ DQG
ZLOO FUHDWH LW ZLWKLQ WKH GDWDEDVH
5HPHPEHU WKDW RQO\ WKH JUDSK UHWXUQHG E\ WKH PHUJH RSHUDWLRQ LV LQ PDQDJHG VWDWH
QRW WKH RQH SDVVHG DV D SDUDPHWHU
REMOVE
REMOVE LV VWUDLJKWIRUZDUG ,Q RXU Employee H[DPSOH LI \RX GHOHWH DQ Employee HQWLW\ LWV
DGGUHVV ZLOO EH GHOHWHG DV ZHOO
Employee employee = entityManager.find(Employee.class, id);
entityManager.remove(employee); // Also removes the address
REFRESH
REFRESH LV VLPLODU WR MERGE 8QOLNH PHUJH WKRXJK WKLV CascadeType RQO\ SHUWDLQV WR
ZKHQ EntityManager.refresh() LV FDOOHG 5HIUHVKLQJ GRHVQ¦W XSGDWH WKH GDWDEDVH ZLWK
FKDQJHV LQ WKH REMHFW LQVWDQFH ,QVWHDG LW UHIUHVKHV WKH REMHFW LQVWDQFH¦V VWDWH IURP WKH
GDWDEDVH $JDLQ WKH FRQWDLQHG UHODWHG HQWLWLHV ZRXOG DOVR EH UHIUHVKHG
Employee employee = entityManager.find(Employee.class, id);
entityManager.refresh(employee); // address would be refreshed too
ALL
ALL LV D FRPELQDWLRQ RI DOO RI WKH SUHYLRXV SROLFLHV DQG LV XVHG IRU WKH SXUSRVHV RI
VLPSOLFLW\
Cascading | 193
When to Use Cascading
<RX GRQ¦W DOZD\V ZDQW WR XVH FDVFDGLQJ IRU HYHU\ UHODWLRQVKLS \RX KDYH )RU LQVWDQFH
\RX ZRXOG QRW ZDQW WR UHPRYH WKH UHODWHG Computer RU TaskV ZKHQ UHPRYLQJ DQ
Employee HQWLW\ IURP WKH GDWDEDVH EHFDXVH WKHVH HQWLWLHV KDYH D OLIH VSDQ WKDW LV XVXDOO\
ORQJHU WKDQ WKH HPSOR\HH <RX PLJKW QRW ZDQW WR FDVFDGH PHUJHV EHFDXVH \RX PD\
KDYH IHWFKHG VWDOH GDWD IURP WKH GDWDEDVH RU VLPSO\ QRW ILOOHG WKH UHODWLRQVKLS LQ RQH
SDUWLFXODU EXVLQHVV RSHUDWLRQ )RU SHUIRUPDQFH UHDVRQV \RX PD\ DOVR QRW ZDQW WR UH
IUHVK DOO WKH UHODWLRQVKLSV DQ HQWLW\ KDV EHFDXVH WKLV ZRXOG FDXVH PRUH URXQG WULSV WR
WKH GDWDEDVH %H DZDUH KRZ \RXU HQWLWLHV ZLOO EH XVHG EHIRUH GHFLGLQJ RQ WKH FDVFDGH
W\SH ,I \RX DUH XQVXUH RI WKHLU XVH WKHQ \RX VKRXOG WXUQ RII FDVFDGLQJ HQWLUHO\ DQG
HQDEOH LW RQ D SHU FDVH EDVLV 5HPHPEHU FDVFDGLQJ LV VLPSO\ D FRQYHQLHQW WRRO IRU
UHGXFLQJ WKH EntityManager $3, FDOOV ,W¦V YHU\ HDV\ WR WULJJHU H[SHQVLYH GDWDEDVH FDOOV
ZKLFK PD\ UHVXOW LQ XQQHFHVVDU\ PXOWLWDEOH MRLQV