您的位置:首页 > 数据库

常用的Hibernate的映射与数据库表的关系(二)

2011-06-05 12:29 337 查看
上篇文章介绍了下多对一的关系关联映射,这次来介绍下其他的几种映射。

首先,介绍下一对多。有人会有疑问:一对多和多对一不是一样的吗?下面我们接着用学生和班级的例子继续来说明下。一对多表示:控制方在一的这一端,比如可以查找属于同一个班级下的所有的学生。这个该怎么实现,试想下你要查找班级下的学生你的Classes类下面就必须要有Student类对象的这个属性字段。private Set<Student> students;利用这个属性来加载属于当前班级下的所有的学生。其他的属性字段同一对多的一样。项目结构图如下:



当前使用的是一对多的映射,配置一般在一的一端。配置如下:

<hibernate-mapping package="com.fendou.hibernate">
<class name="Classes" table="t_classes">
<id name="id" column="cid">
<generator class="native"></generator>
</id>

<property name="name" length="50" column="cname"/>
<set name="students" cascade="all" inverse="true">
<key column="cid"/>
<one-to-many class="Student" />
</set>
</class>
</hibernate-mapping>


注意下当前我们使用的不再是<property>而是<set>标签。set标签中name和property的name一样表示利用Classes这个类的students属性来生成一个字段,该字段名字由<key>来指定也就是cid,并且该字段为Student的外键(由<one-to-many>来指定)。

运行下,同样的会产生如下的代码:

drop table if exists t_classes
drop table if exists t_student
create table t_classes (cid integer not null auto_increment, cname varchar(50), primary key (cid))
create table t_student (sid integer not null auto_increment, sname varchar(50), cid integer, primary key (sid))
alter table t_student add index FK4B907570D95D9B22 (cid), add constraint FK4B907570D95D9B22 foreign key (cid) references t_classes (cid)
配置的这个地方有两点值得我们注意:试想下,在一对多的关系下我们首先加载的是一的这一方,然后是多的那一方,所以代码可以是:

public void testAdd(){
Session session = null;
Transaction tr = null;
try {
session = HibernateUtils.getSession();
//开启事务
tr = session.beginTransaction();
//实例化对象
Student s1 = new Student();
s1.setName("wyb");
//session.save(s1);
Student s2 = new Student();
s2.setName("wym");
//session.save(s2);
Set<Student> set = new HashSet<Student>();
set.add(s2);
set.add(s1);
Classes c = new Classes();
c.setName("FJSE35");
c.setStudents(set);
session.save(c);
tr.commit();
} catch (Exception e) {
e.printStackTrace();
tr.rollback();
}finally{
HibernateUtils.closeSession(session);
}
}


上面的代码我们是直接保存Classes对象的,直接运行的话会产生异常:org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: com.fendou.hibernate.Student。原因是Student在未保存之前是一个瞬时对象,无法被持久化。有两种解决办法第一:先保存Student再保存Classes(把注释去掉),第二:在刚刚的Classes.hbm.xml配置中保留cascade="all"。

第二点值得我们注意的地方是:假设我们的属性字段允许为空,即Student.hbm.xml修改成<property name="name" length="50" column="sname" not-null="true"/>再把Classes.hbm.xml的配置:<set name="students" cascade="all" inverse="true">

去掉cascade="all" inverse="true"同样会报异常。因为我们先加载的是Classes对象,Hibernate只知道有一个Student对象,但对于他的数据约束信息一无所知,加载Student对象的时候并不知道字段可以为空,这样就会违反约束条件。

对于一对多的关联映射,我们一般会修改成双向关联,既可以从多的一端加载也可以从一的一端加载,方便操作。这样的话只需要在多的一端修改配置文件Student.hbm.xml。增加如下配置:<many-to-one name="classes" column="cid"/>注意字段名cid应该和一端的那边一致。

再介绍下:多对多关联关系映射。利用学生与课程之间的关系来解释,一个学生可以选择多门课程,一门课程可以被多个学生选。由于多对多的映射一般也会采用双向关联,所以只介绍双向关联的配置。如果我们用SQL语句来写的话,只需要建立第三张表,然后加入一个联合主键就可以,同理在Hibernate中也一样。现在我们的Student类有private int id;private String name;private Set<Course> courses;三个字段。Course类也有三个字段private int id;private String name;private Set<Student> students;项目结构如图:



Student.hbm.xml和Course.hbm.xml配置如下图:

学生的配置:
<hibernate-mapping package="com.fendou.hibernate">
<class name="Student" table="t_student">
<id name="id" column="sid">
<generator class="native"></generator>
</id>

<property name="name" length="50" column="sname"/>
<set name="courses" table="sc" cascade="all">
<key column="sid" />
<many-to-many column="cid" class="Course" />
</set>
</class>
</hibernate-mapping>

课程的配置:
<hibernate-mapping package="com.fendou.hibernate">
<class name="Course" table="t_course">
<id name="id" column="cid">
<generator class="native"></generator>
</id>

<property name="name" length="50" column="cname"/>
<set name="students" table="sc" cascade="all">
<key column="cid"/>
<many-to-many class="Student" column="sid" />
</set>
</class>
</hibernate-mapping>


介绍下配置:多对多的映射:产生第三张表用来联系前两张表,且有联合主键
<set name="courses" table="sc">
<key column="sid" />
<many-to-many column="cid" class="Course" />
</set>
table表示含有联合主键的第三张表,key表示外键,<many-to-many>中的column表表示另外的一个外键,
class表示另外的一张表。

运行生成的代码如下:

drop table if exists sc
drop table if exists t_course
drop table if exists t_student
create table sc (sid integer not null, cid integer not null, primary key (cid, sid))
create table t_course (cid integer not null auto_increment, cname varchar(50), primary key (cid))
create table t_student (sid integer not null auto_increment, sname varchar(50), primary key (sid))
alter table sc add index FKE50367B2147 (sid), add constraint FKE50367B2147 foreign key (sid) references t_student (sid)
alter table sc add index FKE50BCE53EDB (cid), add constraint FKE50BCE53EDB foreign key (cid) references t_course (cid)
(未完待续,下次介绍继承映射)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: