一对一关联
Hibernate映射实体的一对一关联方式有共享主键方式和唯一外键方式。共享主键就是两个表的主键完全相同,保证一对一。唯一外键就是一个表的唯一外键对应另一个表的唯一主键,来保证一对一。
共享主键方式
唯一外键方式
现实中一个人住一个房间,一个房间是可以多个人住的,这就是多对一的关系,但我们限制每个房间只能住一个人,就成了一对一的关系,所以说一对一关系其实是多对一关系的一种特殊情况。
建立JAVA工程之后生成POJO类如下
可以看到生成的Person.java中没有Integer room_id
,取而代之的是Room room
package org.vo;
/**
* Person entity. @author MyEclipse Persistence Tools
*/
public class Person implements java.io.Serializable {
// Fields
private Integer id;
private Room room;
private String name;
// Constructors
/** default constructor */
public Person() {
}
/** minimal constructor */
public Person(String name) {
this.name = name;
}
/** full constructor */
public Person(Room room, String name) {
this.room = room;
this.name = name;
}
// Property accessors
public Integer getId() {
return this.id;
}
public void setId(Integer id) {
this.id = id;
}
public Room getRoom() {
return this.room;
}
public void setRoom(Room room) {
this.room = room;
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
}
修改Room.java
package org.vo;
import java.util.HashSet;
import java.util.Set;
/**
* Room entity. @author MyEclipse Persistence Tools
*/
public class Room implements java.io.Serializable {
// Fields
private Integer id;
private String address;
//private Set persons = new HashSet(0);
private Person person;
// Constructors
/** default constructor */
public Room() {
}
/** minimal constructor */
public Room(String address) {
this.address = address;
}
/** full constructor */
public Room(String address, Person person) {
this.address = address;
this.person = person;
}
// Property accessors
public Integer getId() {
return this.id;
}
public void setId(Integer id) {
this.id = id;
}
public String getAddress() {
return this.address;
}
public void setAddress(String address) {
this.address = address;
}
public Person getPerson() {
return person;
}
public void setPerson(Person person) {
this.person = person;
}
/*
public Set getPersons() {
return this.persons;
}
public void setPersons(Set persons) {
this.persons = persons;
}
*/
}
修改Person.hbm.xml
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<!--
Mapping file autogenerated by MyEclipse Persistence Tools
-->
<hibernate-mapping>
<class name="org.vo.Person" table="Person" schema="dbo" catalog="test">
<id name="id" type="java.lang.Integer">
<column name="id" />
<generator class="native" />
</id>
<many-to-one name="room" column="room_id" class="org.vo.Room" cascade="all" unique="true"/>
<property name="name" type="java.lang.String">
<column name="name" length="50" not-null="true" />
</property>
</class>
</hibernate-mapping>
修改Room.hbm.xml
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<!--
Mapping file autogenerated by MyEclipse Persistence Tools
-->
<hibernate-mapping>
<class name="org.vo.Room" table="Room" schema="dbo" catalog="test">
<id name="id" type="java.lang.Integer">
<column name="id" />
<generator class="native" />
</id>
<property name="address" type="java.lang.String">
<column name="address" length="100" not-null="true" />
</property>
<one-to-one name="person" class="org.vo.Person" property-ref="room"/>
</class>
</hibernate-mapping>
最后编写测试类Test.java:
package org.test;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.util.HibernateSessionFactory;
import org.vo.Person;
import org.vo.Room;
public class Test {
public static void main(String[] args) {
Person person = new Person();
person.setName("xp");
Room room = new Room();
room.setAddress("NJ-S1-328");
person.setRoom(room);
Session session = HibernateSessionFactory.getSession();
Transaction t = session.beginTransaction();
session.save(person);
t.commit();
session.close();
}
}
执行后查看Person表和Room表如下
可以看到,我们为person设置了room以后,保存person,其room也会保存到数据库中
多对一单向关联
只要把一个房间只能住一个人的限制去掉,每个房间可以住多个人,每个人只能住一个房间,就构成了多对一单向关联
把Person.hbm.xml文件中的
unique="true"去掉
修改Room.java
package org.vo;
import java.util.HashSet;
import java.util.Set;
/**
* Room entity. @author MyEclipse Persistence Tools
*/
public class Room implements java.io.Serializable {
// Fields
private Integer id;
private String address;
//private Set persons = new HashSet(0);
//private Person person;
// Constructors
/** default constructor */
public Room() {
}
/** minimal constructor */
/** full constructor */
public Room(String address) {
this.address = address;
}
// Property accessors
public Integer getId() {
return this.id;
}
public void setId(Integer id) {
this.id = id;
}
public String getAddress() {
return this.address;
}
public void setAddress(String address) {
this.address = address;
}
/*
public Set getPersons() {
return this.persons;
}
public void setPersons(Set persons) {
this.persons = persons;
}
*/
}
- 把Room.hbm.xml中的
<one-to-one name="person" class="org.vo.Person" property-ref="room"/>
去掉
重新编写一下测试类
package org.test;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.util.HibernateSessionFactory;
import org.vo.Person;
import org.vo.Room;
public class Test {
public static void main(String[] args) {
Session session = HibernateSessionFactory.getSession();
Transaction t = session.beginTransaction();
Room room = new Room();
room.setAddress("NJ-S1-413");
Person person1 = new Person();
person1.setName("Jason");
person1.setRoom(room);
Person person2 = new Person();
person2.setName("Lucas");
person2.setRoom(room);
session.save(person1);
session.save(person2);
t.commit();
session.close();
}
}
执行后查表
可以看出,两个person使用了相同的房间。
在这个例子中插入person对象可以同时插入room对象,而插入room对象不会对person表产生影响
一对多双向关联
在多对一双向关联中,根据Person可以看到Room,但是根据Room并不能看到Person,如果我们在Room中加入一个persons ,让Room也可以知道Person,就构成了双向一对多关联。
- 修改Room.java
package org.vo;
import java.util.HashSet;
import java.util.Set;
/**
* Room entity. @author MyEclipse Persistence Tools
*/
public class Room implements java.io.Serializable {
// Fields
private Integer id;
private String address;
private Set persons = new HashSet(0);
//private Person person;
// Constructors
/** default constructor */
public Room() {
}
/** minimal constructor */
public Room(String address) {
this.address = address;
}
/** full constructor */
public Room(String address, Set persons) {
this.address = address;
this.persons = persons;
}
// Property accessors
public Integer getId() {
return this.id;
}
public void setId(Integer id) {
this.id = id;
}
public String getAddress() {
return this.address;
}
public void setAddress(String address) {
this.address = address;
}
public Set getPersons() {
return this.persons;
}
public void setPersons(Set persons) {
this.persons = persons;
}
}
- 修改Room.hbm.xml
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<!--
Mapping file autogenerated by MyEclipse Persistence Tools
-->
<hibernate-mapping>
<class name="org.vo.Room" table="Room" schema="dbo" catalog="test">
<id name="id" type="java.lang.Integer">
<column name="id" />
<generator class="native" />
</id>
<property name="address" type="java.lang.String">
<column name="address" length="100" not-null="true" />
</property>
<set name="persons" inverse="false" cascade="all">
<key column="room_id"/>
<one-to-many class="org.vo.Person"/>
</set>
</class>
</hibernate-mapping>
- 重新编写测试类
package org.test;
import java.util.HashSet;
import java.util.Set;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.util.HibernateSessionFactory;
import org.vo.Person;
import org.vo.Room;
public class Test {
public static void main(String[] args) {
Session session = HibernateSessionFactory.getSession();
Transaction t = session.beginTransaction();
Room room = new Room();
room.setAddress("NJ-S1-219");
Person person1 = new Person();
person1.setName("Paul");
Person person2 = new Person();
person2.setName("Bob");
Set<Person> persons = new HashSet<Person>();
persons.add(person1);
persons.add(person2);
room.setPersons(persons);
session.save(room);
t.commit();
session.close();
}
}
执行后查表:
可以看出,我们为Room设置了Person后,保存Room,Person也被自动保存到数据库中。
多对多单向关联
学生和课程就是多对多的关系,一个学生可以选择多门课程,一门课程也可以被多个学生选择,我们按照下面的关系建立数据库
这里的stu_cour就是一张连接表,表明student和course间的关系
建立Java工程后,用反向工程生成POJO类如下
(stu_cour表不需要做反向工程)
- 修改Student.java
package org.vo;
import java.util.HashSet;
import java.util.Set;
/**
* Student entity. @author MyEclipse Persistence Tools
*/
public class Student implements java.io.Serializable {
// Fields
private Integer id;
private String snumber;
private String sname;
private Integer sage;
private Set courses = new HashSet(0);
// Constructors
/** default constructor */
public Student() {
}
/** minimal constructor */
public Student(String snumber) {
this.snumber = snumber;
}
/** full constructor */
public Student(String snumber, String sname, Integer sage, Set courses) {
this.snumber = snumber;
this.sname = sname;
this.sage = sage;
this.courses = courses;
}
// Property accessors
public Integer getId() {
return this.id;
}
public void setId(Integer id) {
this.id = id;
}
public String getSnumber() {
return this.snumber;
}
public void setSnumber(String snumber) {
this.snumber = snumber;
}
public String getSname() {
return this.sname;
}
public void setSname(String sname) {
this.sname = sname;
}
public Integer getSage() {
return this.sage;
}
public void setSage(Integer sage) {
this.sage = sage;
}
public Set getCourses() {
return courses;
}
public void setCourses(Set courses) {
this.courses = courses;
}
}
- 修改
Student.hbm.xml
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<!--
Mapping file autogenerated by MyEclipse Persistence Tools
-->
<hibernate-mapping>
<class name="org.vo.Student" table="student" schema="dbo" catalog="test">
<id name="id" type="java.lang.Integer">
<column name="ID" />
<generator class="native" />
</id>
<property name="snumber" type="java.lang.String">
<column name="SNUMBER" length="10" not-null="true" />
</property>
<property name="sname" type="java.lang.String">
<column name="SNAME" length="10" />
</property>
<property name="sage" type="java.lang.Integer">
<column name="SAGE" />
</property>
<set name="courses" table="stu_cour" lazy="true" cascade="all">
<key column="SID"></key>
<many-to-many class="org.vo.Course" column="CID"></many-to-many>
</set>
</class>
</hibernate-mapping>
- 编写测试类
package org.test;
import java.util.HashSet;
import java.util.Set;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.util.HibernateSessionFactory;
import org.vo.Course;
import org.vo.Student;
public class Test {
public static void main(String[] args) {
Course cour1= new Course();
Course cour2= new Course();
Course cour3= new Course();
cour1.setCnumber("101");
cour1.setCname("计算机网络");
cour2.setCnumber("102");
cour2.setCname("数据结构");
cour3.setCnumber("103");
cour3.setCname("数据库原理");
Set<Course> courses = new HashSet<Course>();
courses.add(cour1);
courses.add(cour2);
courses.add(cour3);
Student stu = new Student();
stu.setSnumber("20151");
stu.setSname("张灿");
stu.setSage(19);
stu.setCourses(courses);
Session session = HibernateSessionFactory.getSession();
Transaction t = session.beginTransaction();
session.save(stu);
t.commit();
session.close();
}
}
运行后查看数据库
可以看到,为student设置courses后,保存student,student表插入了学生信息,course表插入了课程信息,连接表插入它们的关联信息。
多对多双向关联
在上个例子中,只有student可以控制course,而插入course并不会对student产生影响,我们可以为course也做几乎同样的修改,就可以变成双向关联了。
- 修改Course.java
package org.vo;
import java.util.HashSet;
import java.util.Set;
/**
* Course entity. @author MyEclipse Persistence Tools
*/
public class Course implements java.io.Serializable {
// Fields
private Integer id;
private String cnumber;
private String cname;
private Set students = new HashSet(0);
// Constructors
/** default constructor */
public Course() {
}
/** minimal constructor */
public Course(String cnumber) {
this.cnumber = cnumber;
}
/** full constructor */
public Course(String cnumber, String cname, Set students) {
this.cnumber = cnumber;
this.cname = cname;
this.students = students;
}
// Property accessors
public Integer getId() {
return this.id;
}
public void setId(Integer id) {
this.id = id;
}
public String getCnumber() {
return this.cnumber;
}
public void setCnumber(String cnumber) {
this.cnumber = cnumber;
}
public String getCname() {
return this.cname;
}
public void setCname(String cname) {
this.cname = cname;
}
public Set getStudents() {
return students;
}
public void setStudents(Set students) {
this.students = students;
}
}
- 修改
Course.hbm.xml
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<!--
Mapping file autogenerated by MyEclipse Persistence Tools
-->
<hibernate-mapping>
<class name="org.vo.Course" table="course" schema="dbo" catalog="test">
<id name="id" type="java.lang.Integer">
<column name="ID" />
<generator class="native" />
</id>
<property name="cnumber" type="java.lang.String">
<column name="CNUMBER" length="10" not-null="true" />
</property>
<property name="cname" type="java.lang.String">
<column name="CNAME" length="20" />
</property>
<set name="students" table="stu_cour" lazy="true" cascade="all">
<key column="CID"></key>
<many-to-many class="org.vo.Student" column="SID"></many-to-many>
</set>
</class>
</hibernate-mapping>
- 重新编写测试类
package org.test;
import java.util.HashSet;
import java.util.Set;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.util.HibernateSessionFactory;
import org.vo.Course;
import org.vo.Student;
public class Test {
public static void main(String[] args) {
Student stu1 = new Student();
stu1.setSnumber("20168");
stu1.setSname("朱杰");
stu1.setSage(20);
Student stu2 = new Student();
stu2.setSnumber("20156");
stu2.setSname("王猛");
stu2.setSage(20);
Set students = new HashSet();
students.add(stu1);
students.add(stu2);
Course course=new Course();
course.setCname("算法分析");
course.setCnumber("109");
course.setStudents(students);
Session session = HibernateSessionFactory.getSession();
Transaction t = session.beginTransaction();
session.save(course);
t.commit();
session.close();
}
}
执行后查看数据库
可以看出我们为course设置student后,保存course,也会保存student,和关联信息
参考:
[1]郑阿奇.Java EE实用教程[M].北京:电子工业出版社,2015.2:190-195