一、一對多(@OneToMany)
1、單向一對多模型
假設通過一個客戶實體可以獲得多個地址信息。
對於一對多的實體關系而言,表結構有兩種設計策略,分別是外鍵關聯和表關聯。
(1) 映射策略---外鍵關聯
在數據庫中表customer和表結構address定義,如下:
create table customer (
id int(20) not null auto_increment,
name varchar(100),
primary key(id)
)
create table address (
id int(20) not null auto_increment,
province varchar(50),
city varchar(50),
postcode varchar(50),
detail varchar(50),
customer_id int(20),
primary key (id)
)
注意此時外鍵定義在多的一方,也就是address表中。
此時,表customer映射為實體CustomerEO,代碼如下:
@Entity
@Table(name="customer")
public class CustomerEO implements java.io.Serializable {
@OneToMany(cascade={ CascadeType.ALL })
@JoinColumn(name="customer_id")
private Collection<AddressEO> addresses = new ArrayList<AddressEO>();
...
}
注釋@OneToMany的定義代碼如下:
@Target({METHOD, FIELD}) @Retention(RUNTIME)
public @interface OneToMany {
Class targetEntity() default void.class;
CascadeType[] cascade() default {};
FetchType fetch() default LAZY;
String mappedBy() default "";
}
使用時要注意一下幾點問題:
a、targetEntity屬性表示默認關聯的實體類型。如果集合類中指定了具體類型了,不需要使用targetEntity.否則要指定targetEntity=AddressEO.class。
b、mappedBy屬性用於標記當實體之間是雙向時使用。
(2) 映射策略---表關聯
在上面address表中去掉customer_id字段,在增加一個表ref_customer_address,如下: --客戶地址關系表
create table ref_customer_address (
customer_id int(20) not null,
address_id int(20) not null unique
)
此時表customer映射為CustomerEO實體,代碼如下:
@Entity
@Table(name = "customer")
public class CustomerEO implements java.io.Serializable {
...
@OneToMany(cascade = { CascadeType.ALL })
@JoinTable(name="ref_customer_address",
joinColumns={ @JoinColumn(name="customer_id",referencedColumnName="id")},
inverseJoinColumns={@JoinColumn(name="address_id",referencedColumnName="id")})
private Collection<AddressEO> addresses = new ArrayList<AddressEO>();
...
}
表關聯@JoinTable,定義如下:
@Target({METHOD,FIELD})
public @interface JoinTable {
String name() default "";
String catalog() default "";
String schema() default "";
JoinColumn[] joinColumns() default {};
JoinColumn[] inverseJoinColumns() default {};
UniqueConstraint[] uniqueConstraints default {};
}
其中:
a、該標記和@Table相似,用於標注用於關聯的表。
b、name屬性為連接兩張表的表名。默認的表名為:“表名1”+“-”+“表名2”,上面例子默認的表名為customer_address。
c、joinColumns屬性表示,在保存關系中的表中,所保存關聯的外鍵字段。
d、inverseJoinColumns屬性與joinColumns屬性類似,不過它保存的是保存關系的另一個外鍵字段。
(3) 默認關聯
在數據庫底層為兩張表添加約束,如下:
create table customer_address (
customer_id int(20) not null,
address_id int(20) not null unique
)
alter table customer_address add constraint fk_ref_customer foreign key (customer_id) references customer (id);
alter table customer_address add constraint fk_ref_address foreign key (address_id) references address (id);
這樣,在CustomerEO中只需要在標注@OneToMany即可!
二、多對一@ManyToOne
1、單向多對一模型。
(1) 外鍵關聯
配置AddressEO實體如下:
@Entity
@Table(name="address")
public class AddressEO implements java.io.Serializable {
@ManyToOne(cascade = { CascadeType.ALL })
@JoinColumn(name="customer_id")
private CustomerEO customer;
// ...
}
@ManyToOne定義如下:
@Target({METHOD,FIELD}) @Retention(RUNTIME)
public @interface ManyToOne {
Class targetEntity() default void.class;
CascadeType[] cascade() default {};
FetchType fatch() default EAGER;
boolean optional() default true;
}
(2) 默認關聯
數據庫腳本定義的相關字段的約束,創建外鍵後,直接使用@ManyToOne
三、高級一對多和多對一映射
即雙向關聯模型,確定了雙向關聯後,多的一方AddressEO不變使用@ManyToOne,而CustomerEO實體修改為:
@Entity
@Table(name="customer")
public class CustomerEO {
@OneToMany(mappedBy="customer")
private Collection<AddressEO> addresses = new ArrayList<AddressEO>();
// ...
}
其中,@OneToMany標記中的mappedBy屬性的值為AddressEO實體中所引用的CustomerEO實體的屬性名。
四、多對多(@ManyToMany)
和一對多類型,不在贅述。@ManyToMany標記的定義如下:
@Target({METHOD, FIELD}) @Retention(RUNTIME)
public @interface ManyToMany {
Class targetEntity() default void.class;
CascadeType[] cascade() default {};
FetchType fecth() default LAZY;
String mappedBy() default "";
}
五、最後,談談關於集合類的選擇
在映射關系中可以使用的集合類有Collection、Set、List和Map,下面看下如何選擇。
1、定義時使用接口,初始化使用具體的類。
如Collection可以初始化為ArrayList或HashSet;
Set可以初始化為HashSet;
List可以初始化為ArrayList;
Map可以初始化為HashMap.
2、集合類的選擇
Collection類是Set和List的父類,在未確定使用Set或List時可使用;
Set集合中對象不能重復,並且是無序的;
List集合中的對象可以有重復,並且可以有排序;
Map集合是帶有key和value值的集合。