Hibernate学习笔记一(复杂多对一和一对多关系)

Hibernate中的关联关系是困扰许多初学者的一个难点,但同时它也是Hibernate中的重中之重,我也是初学者,以前学的时候也混过去的,如今想把这些关系给一个一个梳理一下,首先我们来讲下最简单最基础的关联关系映射->一对多和多对一关系,这里我们不讲复杂的概念,而是以代码和配置文件为参考,一步一步揭开一对多的神秘面纱!我们以学生课程为例.首先,我们构造一个学生类,属性有id(与数据表里的主键相对应)name,一个学生选多门课程可以用集合中不允许元素重复的set来表示,这样我们就构造了一个简单的实体,代码如下(省去了getter和setter方法)


public class Student {

 private long id;//与数据表中主键对应
 private String name;
 private Set<Course> courses;//一个学生可以选多门不重复的课程
 }

 


Course类也是如此,说明一点,在这里我们规定一门课只能被一个学生选
public class Course {

 private long id;
 private String name;
 private Student stu;//一门课只能被一个学生选
 }


对象模型我们已经构造好了,接下来我们来构造关系模型,也就是写配置文件.我们对照实体,先把一个一个简单属性(property给写好)
也就是<property name="..." column=""/>简单属性是指类型是基本类型(int long float...)或包装类型(对基本类型的包装)或Stirng类型的属性,除此之外的类型都是复杂类型在写Course关系映射的stu属性时发现它是一个复杂的Student类型,这样就不能用表示简单
属性的<property name="" column=""/>来表示,由于多门不同的课程可以被一个学生选,这就产生了一个多对一关系,即多门Course对应一个stu,在Hibernate用<many-to-one name="stu" column="stu_id"/>来表示,其中name表示实体中复杂类型的名称,因为在hibernate中,实体的每一个属性于必须对应数据库中的一个字段那么在这里stu在数据库中该用什么来表示呢?hibernate处理这种关系是用外键来实现的,也就是这个复杂属性在数据表中的字段是另外一张表(也就是Student实体对应的表)的主键,这里可以指定一个别名,我们指定为stu_id表示这门课程所对应的学生.下面是完整的Course.hbm.xml配置文件
<hibernate-mapping package="com.yuchao.domain">
  <class name="Course" table="t_course">
    <id name="id">
    <generator class="native"></generator>   
    </id>
    <property name="name" type="string"></property>
    <property name="score" type="float"></property>
    <many-to-one name="stu" column="stu_id" ></many-to-one>
  </class>
</hibernate-mapping>
对与Student实体中的set属性,hibernate中有一个<set></set>与之对应.显然,set当中的内容应该是一个个Course,那么我们应该怎样根据一个Student来寻找他选的Course呢,我们思考一下,如果有一门课程的stu_id等于student的id的话,是否就能说明该门
课程是该学生选的了呢?答案是肯定的,比如说English和Math的stu_id都为1,zhangsan的id为1.那么要找到张三所学课程,只需要(select * from course c where c.stu_id=? )?为zhangsan的id.显然这是通过Course中的stu_id来寻找的,因此在set中有一个属性key,用来指明找到该set(也就是一个学生所选的全部课程)是根据数据表中哪一个字段来确定的,再这里当然是stu_id了(就是我们上面指定的course表中的外键)一个学生对应多门课程,在hibernate中是用<one-to-many class="Course"/>来实现的,由于Student中是set集合,hibernate无法知晓set里面装的是什么,所以我们要告诉hibernate,用class="Course"来说明,当然,如果set中用了泛型的话class可以省略,因为这样的话hibernate可以通过反射知道set里面的类型.下面是Student.hbm.xml中的内容
<hibernate-mapping package="com.yuchao.domain">
  <class name="Student" table="t_student">
    <id name="id">
      <generator class="native"></generator>
    </id>
    <property name="name" type="string"></property>
    <set name="courses">
      <key column="stu_id"></key>
      <one-to-many class="Course" />
    </set>
  </class>
</hibernate-mapping>
接下来我们就可以对实体进行一些与数据库的映射操作了

1.插入数据

先new 一个学生,然后在new一些课程,最后执行session.save(...)

如果先save学生的话,在数据库里必然有一个学生id,course.set(stu)的时候,会将stu的id关联到course的stu_id,故执行s.save(course)的时候,course字段的所有值都已经知道,故只有一条insert语句;如果我们先save course的话,此时数据表中的stu_id是没有值的,也就是Null,但是save完course之后再来一条s.sava(stu)语句,那么hibernate会自动地将此stu的id关联到它所对应的course门中,此时stu_id已有,故又有一条update语句

这里我们可以做下试验,在 <many-to-one name="stu" column="stu_id" ></many-to-one>中添加not-null=true就是在save课程的时候stu_id不能为空,那么我们必须先sava学生,得到id,继而得到stu_id之后才能够将course对应的数据表完全填满,否则将会出现

“not-null property references a null or transient value:”(非空属性引用了一个空值)的错误

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值