Hibernate入门教程 第三章
Hibernate一对多、多对一、单边及双边配置
我们上篇文章主要讲了Hibernate的一对一的配置(2种情况),这篇文章主要说一下Hibernate的一对多和多对一的双边配置情况,如果我们只配置其中的一边关系,比如,我们只在一方配置关系那么以上情况就变为单边的一对多,如果我们只配置多方,那么就变成了单边多对一。所以以上我们说了3中情况,其实是差不多的,所以这里我们放到一起讲。很多人可能有的时候搞不清什么时候到底是单边还是双边,其实我们碰到具体的情况我们就知道了,比如学生和班级,这既是一对多、又是多对一,所以我们应该配置双边的。比如用户和邮箱,一个用户有多个邮箱,我们应该配置成单边的一对多的关系。再比如论文系统,多个文章对应一个类型,我们应该配置成单边的多对一关系。当然以上说的一对多和多对一你都可以配成双边的,主要看需求。这里大家只要搞清楚有这几种情况就好了。我们下面开始说重点。
预备知识;
inverse的设置,既然关系设计到单边和双边就涉及到关系到底由一方来维护,还是由多方来维护,Hibernate中默认是由多方来维护;比如学生和班级,学生的多方、班级是单方,那么默认由学生来维护他们之间的关系。
一、配置文件
1、学生类:
public class Student100 implements java.io.Serializable {
// Fields
private Integer sno;
private Class100 class100;
private String name;
// Constructors
/** default constructor */
public Student100() {
}
/** minimal constructor */
public Student100(Integer sno) {
this.sno = sno;
}
/** full constructor */
public Student100(Integer sno, Class100 class100, String name) {
this.sno = sno;
this.class100 = class100;
this.name = name;
}
// Property accessors
public Integer getSno() {
return this.sno;
}
public void setSno(Integer sno) {
this.sno = sno;
}
public Class100 getClass100() {
return this.class100;
}
public void setClass100(Class100 class100) {
this.class100 = class100;
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Student100 [class100=" + class100 + ", name=" + name + ", sno="
+ sno + "]";
}
}2、学生配置文件
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="com.sunny.entity100.Student100" table="student100" catalog="test100">
<id name="sno" type="java.lang.Integer">
<column name="sno" />
<generator class="identity"></generator>
</id>
<property name="name" type="java.lang.String">
<column name="name" length="20" />
</property>
<many-to-one name="class100" class="com.sunny.entity100.Class100">
<column name="class_id" /><!-- Student100表中将会生成一个外键class_id 引用Class100中的id -->
</many-to-one>
</class>
</hibernate-mapping>
3、班级类
public class Class100 implements java.io.Serializable {
// Fields
private Integer id;
private String name;
private Set students = new HashSet();
// Constructors
/** default constructor */
public Class100() {
}
/** minimal constructor */
public Class100(Integer id) {
this.id = id;
}
/** full constructor */
public Class100(Integer id, String name, Set students) {
this.id = id;
this.name = name;
this.students = students;
}
// Property accessors
public Integer getId() {
return this.id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public Set getStudents() {
return students;
}
public void setStudents(Set students) {
this.students = students;
}
}4、班级配置文件
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!--
Mapping file autogenerated by MyEclipse Persistence Tools
-->
<hibernate-mapping>
<class name="com.sunny.entity100.Class100" table="class100" catalog="test100">
<id name="id" type="java.lang.Integer">
<column name="id" />
<generator class="identity"></generator>
</id>
<property name="name" type="java.lang.String">
<column name="name" length="20" />
</property>
<set name="students"><!-- lazy默认为true既打开延时加载 -->
<key>
<column name="class_id" /><!-- 定义集合所对应的数据库表的外键,class_id位student表的外键 -->
</key>
<one-to-many class="com.sunny.entity100.Student100" />
</set>
</class>
</hibernate-mapping>
二、数据库操作
1、插入数据
public static void fun1(){
Session session = HibernateSessionFactory.getSession();
session.beginTransaction();
Student100 s1 = new Student100();
Class100 c = new Class100();
c.setName("三年二班");
s1.setName("apache");
s1.setClass100(c);//默认是多方维护关系,既关系由Student来维护
session.save(c);
session.save(s1);
session.getTransaction().commit();
session.close();
}
s1.setClass100(c);我们看到这里由Student来维护关系的,如果我们想让Class来维护关系应该这么做呢,如下:
在班级的配置文件中加上这一句
<set name="students" inverse="false"> 既不是由对方来控制关系那么就是自已来控制关系啦
那么我们fun1改写为如下:
public static void fun1_1(){
Session session = HibernateSessionFactory.getSession();
session.beginTransaction();
Student100 s1 = new Student100();
s1.setName("apache");
Class100 c = new Class100();
c.setName("三年二班");
c.getStudents().add(s1);//Class维护关系
session.save(s1);
session.save(c);
session.getTransaction().commit();
session.close();
}补充:由于inverse一般设置在set上面,在一对一关系中,我们应该没有办法控制关系由谁来维护,一般是在有外键的哪一方维护的(个人认为)
2、查询
//查询
public static void fun2(){
Session session = HibernateSessionFactory.getSession();
session.beginTransaction();
Query query = session.createQuery("from Student100");
List<Student100> list = query.list();
for(Student100 stu:list){
System.out.println(stu.getClass100().getName());
}
}产生n+1条sql语句,因为默认fetch为select//fetch的使用
public static void fun4(){
Session session = HibernateSessionFactory.getSession();
session.beginTransaction();
Query query = session.createQuery("from Class100 c left join fetch c.students");
//Query query = session.createQuery("from Student100 s");
List<Class100> ss = query.list();
for(Class100 s : ss){
System.out.println(s);
}
}由于lazy设置为true(默认),所以我们要用fetch把学生从班级里抓取出来,当然也可以不抓取,那么当要用到学生信息时候,Hibernate会自动抓取
3、删除与更新简单,没有设置级联的时候要考虑约束
三、对应相应的一对多和多对一的单边配置,只要删除对应的关系就可以了,这里不再啰嗦
说明:比如一对多的单边关系,则关系维护就有一方维护,比如本来中,我们删除Student中Class和相关的配置文件中的配置。现在的关系是一个班级对应多个学生这样的一对多的单边关系。那么这个时候关系就有一方既班级来维护,Hibernate中如果双边关系都在,则默认是由多方维护关系,如果是单边的,那么谁在谁维护关系,在此说明!

180

被折叠的 条评论
为什么被折叠?



