从关联关系的数量上来看,单向关联可分为
1)单向1-1
2)单向1-N
3)单向N-1
4)单向N-N
从关联关系的数量上来看,双向关联可分为
1)双向1-1
2)双向1-N
3)双向N-N
单向N-1
public class Address{
@ManyToOne(opentional=false,cascade=CascadeType.ALL,fetch=FetchType.LAZY,targetEntity=Person.class)
//下面的注解用于映射外键列
@JoinColumn(name=”person_id”,nullable=false,updatable=false)
private Person person;
}
对于1-N关联关系,不管是单向还是双向,都需要在N的一端使用@ManyToOne
cascade:非必须,指定JPA采用怎样的级联策略
1)CascadeType.ALL:将所有持久化操作都级联到关联实体
2)CascadeType.MERGE:将merge操作都级联到关联实体
3)CascadeType.PERSISI:将persist操作都级联到关联实体
4)CascadeType.REFRESH:将refresh操作都级联到关联实体
5)CascadeType.REMOVE:将remove操作都级联到关联实体
fetch:非必须,指定抓取关联实体时的抓取策略,支持
1)FetchType.EAGER:立即抓取关联实体。默认值
2)FetchType.LAZY:延迟抓取关联实体。
optional:非必须,指定关联关系是否可选
targetEntity:非必须,指定关联实体的类名。默认情况下JPA将通过反射来判断关联实体的类名
@JoinColumn属性说明
1)columnDefinition,非必须,指定JPA使用该属性值指定SQL片段来创建外键列
2)name:非必须,指定外键列的列名
3)insertable:非必须,指定该列是否包含在JPA生成的insert语句中,默认为true
4)updatable:非必须,指定该列是否包含在JPA生成的update语句中,默认为true
5)nullable:非必须,指定该列是否允许null,默认为true
6)table:非必须,指定该列所在数据表的表名
7)unique:非必须,指定是否为该列增加唯一约束
8)referencedColumnName:非必须,指定该列所参照的主键列的列名
可以使用@JoinColumns来组合@JoinColumn
单向1-1
使用@OneToOne来修饰,属性说明
cascade:非必须,取值同上
fetch:非必须,取值同上
mappedBy:非必须,该属性合法的属性值为关联实体的属性名,指定关联实体中哪个属性可引用到当前实体
optional:非必须,同上
targetEntity:非必须,同上
对于mappedBy属性,可在@OneToOne、@OneToMany、@ManyToMany中使用,不能在@ManyToOne中使用,除了上述的作用外,还用于指定该属性出现的当前实体不再控制关联关系——类似于Hibernate中设置了inver=”true”。一旦为@OneToMany、@ManyToMany指定了mappedBy属性,这两个Annotation将不能和@JoinColumn、@JoinTable一起使用。
外键列会被添加唯一约束
单向1-N
实体类需要使用集合属性,以set形式出现。这样,1-N(还包括N-N)都需要增加一个set类型的属性
推荐在@OneToOne、@OneToMany、@ManyToOne、@ManyToMany这四个注解中指定targetEn。指定该属性可以避免JPA通过反射去获取关联实体的类型,从而提高性能。
1-N关联需要使用@OneToMany来修饰Set属性,属性说明
cascade:非必须,取值同上
fetch:非必须,取值同上
mappedBy:非必须,取值同上
targetEntity:非必须,取值同上
public class Person{
@OneToMany(cascade=CascadeType.ALL,fetch=FetchType.LAZY,targetEntity=Address.class)
@JoinColumn(name=”person_id”,nullable=false)
private Set<Address>=new HashSet<Address>();
}
单向N-N
N-N的关联必须使用中间表。除了使用@ManyToMany来修饰Set外,还需要使用@JoinTable来修饰Set
@ManyToMany属性如下
cascade:非必须,取值同上
fetch:非必须,取值同上
mappedBy:非必须,取值同上
targetEntity:非必须,取值同上
@JoinTable专门用于N-N关系,属性如下
name:非必须,指定该连接表的表名
catalog:非必须,设置实体所映射的表放入指定的catalog内,如果没有则放入默认的catalog内
schema:非必须,设置实体锁映射的表放入指定的schema内,如果没有则放入默认的schema内
targetEntity:非必须,取值同上
joinColumns:非必须,接受多个@JoinColumn,用于配置外键列信息,参照当前实体的主键列
inverseJoinColumns:非必须,接受多个@JoinColumn,用于配置外键列信息,参照当前实体的关联实体的主键列
uniqueConstraints:非必须,用于为中间表增加唯一约束
public class Peson{
@ManyToMany(cascade=CascadeType.ALL,fetch=FetchType.LAZY,targetEntity=Address.class)
@JoinTable(name=”person_address”,joinColumns=@JoinColumn(name=”person_id”)inverseJoinColumns=@JoinColumn(name=”address_id”))
private Set<Address> address=new HashSet<Address>();
}
双向1-1
需要在两边的实体类增加@OneToOne修饰属性,可以在关联实体一边的@OneToOne中增加mappedBy属性,增加改属性的实体不再控制关联关系
public class Person{
@OneToOne(mappedBy=”person”,cascade=CascadeType.ALL,fetch=FetchType.LAZY,targetEntity=Address.class)
private Address address;
}
上例中Person不再控制关联关系,所以Person的关联实体Address就需要控制关联关系,由于JPA会采用基于外键的方式来建立底层数据库中1-1关联关系,因此在Address中还需要使用@JoinColumn。
public class Address{
@OneToOne(optional=false,cascade=CascadeType.ALL,fetch-FetchType.LAZY,targetEntity=Person.class)
@JoinColumn(name=”person_id”,nullable=false,updatable=false)
private Person person;
}
需要指出的是,由于1-1关联的双方本质上是平等的,一次底层数据库可以在1-1关联的两个数据表的任意一边增加外键列,并通过外键列来维护实体之间的参照关系。但对于JPA而言,需要一个具体的规则:如果双向1-1关联的某个实体类中的@OneToOne没有指定mappedBy属性,并使用了@JoinColumn,那么JPA将会在该实体对应的数据表中增加外键列。因此对于上面的程序,JPA会在Address实体对应的数据表中增加外键列。
双向1-N关联
对于1-N关联,在JPA中应该尽量映射成双向关联,而且尽量不要让1的一端来控制关联关系,而应该在N的一端来控制关联关系
双向的1-N与N-1是完全相同的两种情形。
1的一端应该使用@OneToMany修饰记录关联实体的Set属性,由于程序通常不会让1的一端来控制关联关系,因此使用@OneToMany时应增加mappedBy属性,N的一端则应该使用@ManyToOne修饰记录关联实体的属性。除此之外,还应该在N的一端的实体上使用@JoinColumn来配置外键列信息。
public class Peson{
// 1端的代码
@OneToMany(cascade=CascadeType.ALL,mappedBy=”person”,targetEntity=Address.class)
private Set<Address> addresses;
}
public class Address{
// N端的代码
@ManyToOne(fetch=FetchType.EAGER,targetEntity=Person.class,cascade=CascadeType.ALL)
@JoinColum(name=”person_id”,nullable=true)
private Person person;
}
双向N-N
关联
关联实体的两边都应该增加set属性,两边都使用@ManyToMany来修饰,需要在一端的关联实体中增加@JoinTable来管理连接表信息。可通过在一端的@ManyToMany中增加mappedBy属性,增加该属性的实体将不再控制关联关系,因此该实体的set属性不应该使用#JoinTable修饰
public class Address{
@ManyToMany(cascade=CascadeType.ALL,mappedBy=”addresses”,fetch=FecthType.LAZY,targetEntity=Person.class)
private Set<Person> persons=new HashSet<Person>();
}
public class Person{
@ManyToMany(cascade=CascadeType.ALL,fetch=FetchType.LAZY,targetEntity=Address.class)
@JoinTable(
name=”person_address”,
joinColumns=@JoinColumn(name=”person_id”),
inverseJoinColumn=@JoinColumn(name=”address_id”)
)
private Set<Address> addresses=new HashSet<Address>();
}