@OneToMany、@ManyToOne以及@ManyToMany讲解
一、一对多(@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值的集合。