hibernate联系关系映射(一对多)

hibernate关联映射(一对多)

这篇博客将会给大家带来hibernate的关联映射的学习。在现实生活中,不仅只是一对一的映射关系,更多的是一对多,多对多等。

一对多单项关联映射

这里我以网盘为例,一个用户可以拥有多个文件,及用户和文件之间是一对多的关系。
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联系关系映射(一对多)
可以看到hibernate是首先插入所有的多方,然后利用update来更新一对多的关系。
hibernate联系关系映射(一对多)
可以看到在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();                

hibernate联系关系映射(一对多)
此时,所有的数据都还继续存在,只是将关联删除。

一对多双向关联

之前关于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);这样的方式来建立关联的。存入数据也是存入的多端数据即可。
hibernate联系关系映射(一对多)
此时对于一对多的双向关联,一的一端和多的一端都可以同时维护数据,那么如果我只想让多的一端来维护数据,可以添加一个inverse=”true”这个关键字。

<set name="files" cascade="all" inverse="true">
    <key column="u_id"/>
    <one-to-many class="a.b.c.UpFile"/>
</set>

好了,关于hibernate一对多的学习就到这里了。