这篇博客将会给大家带来hibernate的关联映射的学习。在现实生活中,不仅只是一对一的映射关系,更多的是一对多,多对多等。
这里我以网盘为例,一个用户可以拥有多个文件,及用户和文件之间是一对多的关系。
user实体类:
public class Users {
private int uid;
private String uname;
//用户上传的所有文件 // one方 可以获取 many方
private Set<UpFile> files = new HashSet<UpFile>();
public Users() {
super();
// TODO Auto-generated constructor stub
}
public Users(int uid, String uname) {
super();
this.uid = uid;
this.uname = uname;
}
public int getUid() {
return uid;
}
public void setUid(int uid) {
this.uid = uid;
}
public String getUname() {
return uname;
}
public void setUname(String uname) {
this.uname = uname;
}
public Set<UpFile> getFiles() {
return files;
}
public void setFiles(Set<UpFile> files) {
this.files = files;
}
}
UpFile实体类如下:
public class UpFile {
private int fid;
private String fileName;
private int fsize;
public UpFile() {
super();
// TODO Auto-generated constructor stub
}
public UpFile(int fid, String fileName, int fsize) {
super();
this.fid = fid;
this.fileName = fileName;
this.fsize = fsize;
}
public int getFid() {
return fid;
}
public void setFid(int fid) {
this.fid = fid;
}
public String getFileName() {
return fileName;
}
public void setFileName(String fileName) {
this.fileName = fileName;
}
public int getFsize() {
return fsize;
}
public void setFsize(int fsize) {
this.fsize = fsize;
}
}
可以看到,一对多的设置只是在一方通过set集合来实现的,因为set集合是不能重复的,所以使用它。
Users.hbm.xml
<?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="a.b.c.Users">
<id name="uid">
<generator class="native"/>
</id>
<property name="uname"/>
<!-- one-to-many -->
<set name="files">
<key column="u_id"/>
<one-to-many class="a.b.c.UpFile"/>
</set>
</class>
</hibernate-mapping>
UpFile.hbm.xml
<hibernate-mapping>
<class name="a.b.c.UpFile">
<id name="fid">
<generator class="native"/>
</id>
<property name="fileName"/>
<property name="fsize"/>
</class>
</hibernate-mapping>
通过<set></set>
标签实现的一对多关系。对于user表的主键作为upfile表的外键。
此时,执行一条插入操作:
session.beginTransaction();
Users u = new Users(0,"赵六");
UpFile f = new UpFile(0,"ccc.txt",453);
UpFile f2 = new UpFile(1,"bbb.txt",500);
u.getFiles().add(f); //one端集合关系
u.getFiles().add(f2);
session.save(f);
session.save(f2);
session.save(u);
此时控制台打印的sql语句如下:
可以看到hibernate是首先插入所有的多方,然后利用update来更新一对多的关系。
可以看到在upfile中,有一个u_id作为外键。
在上面的一对多的插入操作当中,首先插入了两个UpFile,然后插入单个user,其实不必这么麻烦,可以配置级联操作:
<set name="files" cascade="all">
<key column="u_id"/>
<one-to-many class="a.b.c.UpFile"/>
</set>
cascade=”all”这里,我配置值为all,表示基于user的所有操作都会关联到和其关联的UpFile表的数据,cascade有如下一些值:
delete,
update,
all,
none
在配置了级联操作以后,执行插入就可以只插入User了,hibernate会将和该user关联的所有upfile都进行添加操作:
session.beginTransaction();
Users u = new Users();
u.setUname("adsf");
UpFile f = new UpFile("ccc.txt",453);
UpFile f2 = new UpFile("bbb.txt",500);
u.getFiles().add(f); //one端集合关系
u.getFiles().add(f2);
session.save(u);
session.getTransaction().commit();
<set name="files" cascade="all" lazy="false">
<key column="u_id"/>
<one-to-many class="a.b.c.UpFile"/>
</set>
如果配置lazy=”false”表示立即加载。此时只要查询每一个user的时候,都会将该user对应的upfile查询出来,如果lazy=”true”,那么当查询user的时候,不会立即将该user对应的upfile查询出来,而是在使用到的时候,才根据该user的主键去upfile表中查找。
Configuration cfg = new Configuration().configure();
SessionFactory factory = cfg.buildSessionFactory();
Session session = factory.openSession();
Transaction transaction = session.beginTransaction();
Users u1 = (Users)session.get(Users.class, 1);
UpFile upFile = (UpFile) session.get(UpFile.class,2);
u1.getFiles().remove(upFile);
transaction.commit();
session.close();
此时,所有的数据都还继续存在,只是将关联删除。
之前关于user和upfile的一对多的关联是单向的,也就是说我们只能通过user来获得和操作upfile,反过来则是不行的,那么怎么配置”一对多的双向关联”??
1.需要在Upfile类中增加user属性,并为该属性提供get和set方法
private Users users;
2.配置映射文件:
Users.hbm.xml
<hibernate-mapping>
<class name="a.b.c.Users">
<id name="uid">
<generator class="increment"/>
</id>
<property name="uname"/>
<!-- one-to-many -->
<set name="files" cascade="all">
<key column="u_id"/>
<one-to-many class="a.b.c.UpFile"/>
</set>
</class>
</hibernate-mapping>
Upfile.hbm.xml
<hibernate-mapping>
<class name="a.b.c.UpFile">
<id name="fid">
<generator class="increment"/>
</id>
<property name="fileName"/>
<property name="fsize"/>
<many-to-one name="users" column="u_id" cascade="all"></many-to-one>
</class>
</hibernate-mapping>
此时如果从多的一端来维护数据,比如我在这里插入为uid=1的user插入在关联一个upfile文件:
Configuration cfg = new Configuration().configure();
SessionFactory factory = cfg.buildSessionFactory();
Session session = factory.openSession();
try {
session.beginTransaction();
Users u = (Users) session.get(Users.class,1);
UpFile f = new UpFile("fff.txt",453);
UpFile f2 = new UpFile("ttt.txt",500);
f.setUsers(u);
f2.setUsers(u);
session.save(f);
session.save(f2);
session.getTransaction().commit();
} catch (HibernateException e) {
e.printStackTrace();
session.getTransaction().rollback();
}
session.close();
可以看到,这个时候就是通过f2.setUsers(u);这样的方式来建立关联的。存入数据也是存入的多端数据即可。
此时对于一对多的双向关联,一的一端和多的一端都可以同时维护数据,那么如果我只想让多的一端来维护数据,可以添加一个inverse=”true”这个关键字。
<set name="files" cascade="all" inverse="true">
<key column="u_id"/>
<one-to-many class="a.b.c.UpFile"/>
</set>
好了,关于hibernate一对多的学习就到这里了。
原文地址:http://blog.csdn.net/mockingbirds/article/details/46489725