不管是双向还是单向关联,数据库表的设计是一样的,一般都是在N的一方增加外键(如果在1的一方增加外键势必会造成冗余)
单向N-1关联
以Group和User为例,一个Group可以有多个User,一个User只能对应一个Group,典型的一对多(多对一)的案列
Annotation方式
对于N-1关联(无论单向还是双向),都需要在N的一方给关联属性加上@ManyToOne注解
@ManyToOne注解有以下属性:
属性 | 是否必需 | 说明 |
---|---|---|
cascade | 否 | 指定Hibernate对关联实体采用的级联策略 |
fetch | 否 | 指定抓取关联实体时的抓取策略,该属性值有FetchTyoe.LAZY和FetchType.EAGER(@ManyToOne注解的默认值),LAZY是指真正用到关联实体才会去数据库获取 |
optional | 否 | 该属性指定关联关系是否可选 |
targetEntity | 否 | 该属性指定关联实体的类名,默认情况下,Hibernate将通过反射来判断关联实体的类名 |
User实体:
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
@Entity
@Table(name="t_user")
public class User {
private int id;
private String name;
private Group group;
@Id
@GeneratedValue
public int getId() {
return id;
}
@Column(length=50)
public String getName() {
return name;
}
//关联实体属性加上@ManyToOne注解
@ManyToOne
//指定映射的外键字段
@JoinColumn(
name="group_id",
referencedColumnName="id",
unique=false
)
public Group getGroup() {
return group;
}
public void setGroup(Group group) {
this.group = group;
}
public void setId(int id) {
this.id = id;
}
public void setName(String name) {
this.name = name;
}
}
Group实体:
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;
@Entity
@Table(name="t_group")
public class Group {
private int id;
private String name;
private String description;
@Id
@GeneratedValue
public int getId() {
return id;
}
@Column(length=50)
public String getName() {
return name;
}
public String getDescription() {
return description;
}
public void setId(int id) {
this.id = id;
}
public void setName(String name) {
this.name = name;
}
public void setDescription(String description) {
this.description = description;
}
}
控制台输出的建表语句:
XML方式
user.hbm.xml文件
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="pers.msidolphin.hibernate.many2one">
<class name="User" table="t_user">
<id name="id" column="id">
<generator class="native"></generator>
</id>
<property name="name" column="name" length="50"/>
<many-to-one name="group">
<column name="group_id" unique="false"></column>
</many-to-one>
</class>
</hibernate-mapping>
group.hbm.xml文件
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="pers.msidolphin.hibernate.many2one">
<class name="Group" table="t_group">
<id name="id" column="id">
<generator class="native"></generator>
</id>
<property name="name" column="name" length="50"/>
<property name="description" column="description"/>
</class>
</hibernate-mapping>
结果同上
单向1-N关联
单向1-N关联的实体类设计不同与N-1关联,需要在1的一方增加集合属性,该集合用于存储关联实体.
Annotation方式
为了映射1-N关联,需要在集合属性上加上@OneToMany注解
@OneToMany注解有以下属性:
属性 | 是否 必需 | 说明 |
---|---|---|
cascade | 否 | 指定Hibernate对关联实体采用的级联策略 |
fetch | 否 | 指定抓取关联实体时的抓取策略,该属性值有FetchTyoe.LAZY和FetchType.EAGER(@ManyToOne注解的默认值),LAZY是指真正用到关联实体才会去数据库获取 |
orphanRemoval | 否 | 该属性设置某个实体所关联的父实体不存在(即该实体对应记录的外键为null)时是否删除 |
mappedBy | 否 | 该属性指定关联实体的哪一个属性用于维护关联关系(外键),对于双向一定要在1的一方设置mappedBy,否则双方都会建立外键 |
targetEntity | 否 | 该属性指定关联实体的类名,默认情况下,Hibernate将通过反射来判断关联实体的类名 |
Group实体:
import java.util.HashSet;
import java.util.Set;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToMany;
import javax.persistence.Table;
@Entity
@Table(name="t_group")
public class Group {
private int id;
private String name;
private String description;
private Set<User> users = new HashSet<User>();
@Id
@GeneratedValue
public int getId() {
return id;
}
@Column(length=50)
public String getName() {
return name;
}
public String getDescription() {
return description;
}
//集合属性加上了@OneToMany注解
@OneToMany
//显式指定映射的外键字段
@JoinColumn(
name="group_id",
referencedColumnName="id",
unique=false
)
public Set<User> getUsers() {
return users;
}
public void setId(int id) {
this.id = id;
}
public void setUsers(Set<User> users) {
this.users = users;
}
public void setName(String name) {
this.name = name;
}
public void setDescription(String description) {
this.description = description;
}
}
User实体:
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;
@Entity
@Table(name="t_user")
public class User {
private int id;
private String name;
@Id
@GeneratedValue
public int getId() {
return id;
}
@Column(length=50)
public String getName() {
return name;
}
public void setId(int id) {
this.id = id;
}
public void setName(String name) {
this.name = name;
}
}
控制台输出的建表语句:
可以看到和前面的多对一是一样的,因为外键总是处于多的一方的
XML方式
group.hbm.xml文件
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="pers.msidolphin.hibernate.one2many">
<class name="Group" table="t_group">
<id name="id" column="id">
<generator class="native"></generator>
</id>
<property name="name" column="name" length="50"/>
<property name="description" column="description"/>
<!--映射集合属性-->
<set name="users">
<key column="group_id" unique="false"></key>
<!--关联属性完整类名-->
<one-to-many class="pers.msidolphin.hibernate.one2many.User"/>
</set>
</class>
</hibernate-mapping>
结果同上
双向N-1 or 1-N关联
关于双向的N-1或1-N关联实际上是一样的,双方都需要增加对关联属性的访问,N的一方增加关联实体的引用属性,1的一方增加集合属性,集合元素为关联实体
Annotation方式
对于双向关联,一定要设置mappedBy属性,而且不要让1的一方控制关联关联,而是N方控制关联关系(即外键总是建立在多的一方的),并且在多的一方设置@ManyToOne注解,在1的一方设置@OneToMany注解
User实体:
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
@Entity
@Table(name="t_user")
public class User {
private int id;
private String name;
private Group group;
@Id
@GeneratedValue
public int getId() {
return id;
}
@Column(length=50)
public String getName() {
return name;
}
@ManyToOne(cascade={javax.persistence.CascadeType.ALL})
@JoinColumn(
name="group_id",
referencedColumnName="id",
unique=false
)
public Group getGroup() {
return group;
}
public void setId(int id) {
this.id = id;
}
public void setName(String name) {
this.name = name;
}
public void setGroup(Group group) {
this.group = group;
}
}
Group实体:
package pers.msidolphin.hibernate.one2many_many2one;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;
@Entity
@Table(name="t_group")
public class Group {
private int id;
private String name;
private String description;
private Set<User> users = new HashSet<User>();
@Id
@GeneratedValue
public int getId() {
return id;
}
@Column(length=50)
public String getName() {
return name;
}
public String getDescription() {
return description;
}
//一定要记得设置mappedBy
@OneToMany(mappedBy="group")
public Set<User> getUsers() {
return users;
}
public void setId(int id) {
this.id = id;
}
public void setUsers(Set<User> users) {
this.users = users;
}
public void setName(String name) {
this.name = name;
}
public void setDescription(String description) {
this.description = description;
}
}
控制台输出的建表语句:
XML方式
group.hbm.xml文件
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="pers.msidolphin.hibernate.one2many_many2one">
<class name="Group" table="t_group">
<id name="id" column="id">
<generator class="native"></generator>
</id>
<property name="name" column="name" length="50"/>
<property name="description" column="description"/>
<set name="users">
<!-- 注意:对于xml方式的多对一/一对多双向关联,指定的映射字段名称时两端务必保持一致,否则会创建两个外键 -->
<key column="group_id" unique="false"></key>
<one-to-many class="pers.msidolphin.hibernate.one2many_many2one.User"/>
</set>
</class>
</hibernate-mapping>
user.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="pers.msidolphin.hibernate.one2many_many2one">
<class name="User" table="t_user">
<id name="id" column="id">
<generator class="native"></generator>
</id>
<property name="name" column="name" length="50"/>
<many-to-one name="group">
<!-- 注意:对于xml方式的多对一/一对多双向关联,指定的映射字段名称时两端务必保持一致,否则会创建两个外键 -->
<column name="group_id" unique="false"></column>
</many-to-one>
</class>
</hibernate-mapping>