一、一对多(@OneToMany)
1、单向一对多模型
假设通过一个客户实体可以获得多个地址信息。
对于一对多的实体关系而言,表结构有两种设计策略,分别是外键关联和表关联。
(1)映射策略---外键关联
在数据库中表customer和表结构address定义,如下:
01 | create table customer ( |
02 | id int (20) not null auto_increment, |
07 | create table address ( |
08 | id int (20) not null auto_increment, |
注意此时外键定义在多的一方,也就是address表中。
此时,表customer映射为实体CustomerEO,代码如下:
2 | @Table (name= "customer" ) |
3 | public class CustomerEO implements java.io.Serializable { |
4 | @OneToMany (cascade={ CascadeType.ALL }) |
5 | @JoinColumn (name= "customer_id" ) |
6 | private Collection<AddressEO> addresses = new ArrayList<AddressEO>(); |
注释@OneToMany的定义代码如下:
1 | @Target ({METHOD, FIELD}) @Retention (RUNTIME) |
2 | public @interface OneToMany { |
3 | Class targetEntity() default void . class ; |
4 | CascadeType[] cascade() default {}; |
5 | FetchType fetch() default LAZY; |
6 | String mappedBy() default "" ; |
使用时要注意一下几点问题:
a、targetEntity属性表示默认关联的实体类型。如果集合类中指定了具体类型了,不需要使用targetEntity.否则要指定targetEntity=AddressEO.class。
b、mappedBy属性用于标记当实体之间是双向时使用。
(2)映射策略---表关联
在上面address表中去掉customer_id字段,在增加一个表ref_customer_address,如下:
2 | create table ref_customer_address ( |
3 | customer_id int (20) not null , |
4 | address_id int (20) not null unique |
此时表customer映射为CustomerEO实体,代码如下:
02 | @Table (name = "customer" ) |
03 | public class CustomerEO implements java.io.Serializable { |
05 | @OneToMany (cascade = { CascadeType.ALL }) |
06 | @JoinTable (name= "ref_customer_address" , |
07 | joinColumns={ @JoinColumn (name= "customer_id" ,referencedColumnName= "id" )}, |
08 | inverseJoinColumns={ @JoinColumn (name= "address_id" ,referencedColumnName= "id" )}) |
09 | private Collection<AddressEO> addresses = new ArrayList<AddressEO>(); |
表关联@JoinTable,定义如下:
1 | @Target ({METHOD,FIELD}) |
2 | public @interface JoinTable { |
3 | String name() default "" ; |
4 | String catalog() default "" ; |
5 | String schema() default "" ; |
6 | JoinColumn[] joinColumns() default {}; |
7 | JoinColumn[] inverseJoinColumns() default {}; |
8 | UniqueConstraint[] uniqueConstraints default {}; |
其中:
a、该标记和@Table相似,用于标注用于关联的表。
b、name属性为连接两张表的表名。默认的表名为:“表名1”+“-”+“表名2”,上面例子默认的表名为customer_address。
c、joinColumns属性表示,在保存关系中的表中,所保存关联的外键字段。
d、inverseJoinColumns属性与joinColumns属性类似,不过它保存的是保存关系的另一个外键字段。
(3)默认关联
在数据库底层为两张表添加约束,如下:
1 | create table customer_address ( |
2 | customer_id int (20) not null , |
3 | address_id int (20) not null unique |
5 | alter table customer_address add constraint fk_ref_customer foreign key (customer_id) references customer (id); |
7 | alter table customer_address add constraint fk_ref_address foreign key (address_id) references address (id); |
这样,在CustomerEO中只需要在标注@OneToMany即可!
二、多对一@ManyToOne
1、单向多对一模型。
(1)外键关联
配置AddressEO实体如下:
02 | @Table (name= "address" ) |
03 | public class AddressEO implements java.io.Serializable { |
05 | @ManyToOne (cascade = { CascadeType.ALL }) |
06 | @JoinColumn (name= "customer_id" ) |
07 | private CustomerEO customer; |
@ManyToOne定义如下:
1 | @Target ({METHOD,FIELD}) @Retention (RUNTIME) |
2 | public @interface ManyToOne { |
3 | Class targetEntity() default void . class ; |
4 | CascadeType[] cascade() default {}; |
5 | FetchType fatch() default EAGER; |
6 | boolean optional() default true ; |
(2)默认关联
数据库脚本定义的相关字段的约束,创建外键后,直接使用@ManyToOne
三、高级一对多和多对一映射
即双向关联模型,确定了双向关联后,多的一方AddressEO不变使用@ManyToOne,而CustomerEO实体修改为:
2 | @Table (name= "customer" ) |
3 | public class CustomerEO { |
5 | @OneToMany (mappedBy= "customer" ) |
6 | private Collection<AddressEO> addresses = new ArrayList<AddressEO>(); |
其中,@OneToMany标记中的mappedBy属性的值为AddressEO实体中所引用的CustomerEO实体的属性名。
四、多对多(@ManyToMany)
和一对多类型,不在赘述。@ManyToMany标记的定义如下:
1 | @Target ({METHOD, FIELD}) @Retention (RUNTIME) |
2 | public @interface ManyToMany { |
3 | Class targetEntity() default void . class ; |
4 | CascadeType[] cascade() default {}; |
5 | FetchType fecth() default LAZY; |
6 | 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值的集合。