Hibernate外键关联的对象操作

Hibernate框架是一个自动生成数据表,sql语句的超强框架,一般的增删改查操作起来与我们之前操作数据库没什么大的区别,调用相应的方法即可.但是当我们的数据表中有外键关联,并且要处理这些外键关联的对象数据时,hibernate提供了独特并且更有效的方法.

数据表与数据表的外键关联主要是用于对象的一对多(多对一)和多对多的情况.hibernate也是针对这两种情况作了一些处理

一对多(多对一)

这里假设有一组模型是父亲(Fathers)和儿子(Sons),一个父亲可以有多个儿子,但是一个儿子只有一个父亲,是一个一对多的模型

首先java实体类的书写

public class Fathers implements Serializable{

    private String id;
    private String username;
    private Set<Sons> sons = new HashSet<Sons>();

    get/set...
}
public class Sons implements Serializable{

    private String id;
    private String name;
    private Fathers father;

    set/get...
}

在这个模型中,一对多,一指的是father,多指的是sons.在java实体中"一"的那一方需要定义一个泛型是"多"的set,用来存放信息,"多"的那一方则需要定义一个"一"类型的成员变量在这个例子中,father的类中需要放一个sons类型的set.Sons类中需要放一个fathers成员变量.

配置文件书写

Fathers.hbm.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC 
    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">

<hibernate-mapping package="domain" >
	<class name="Fathers" table="father" >

		<id name="id">
			<generator class="uuid"></generator>
		</id>
		<property name="username" column="username"></property>
		<!-- inverse反转控制,把维护的权利交出去-->

        <!-- name:"一"的那一方的set的名称
             colume:"多"的那一方生成表时的外键名
             class:"多"的那一方的类名
                -->
		<set name="sons" inverse="true">
			<key column="fatherid"></key>
			<one-to-many class="Sons"></one-to-many>
		</set>
	</class>
</hibernate-mapping>

Sons.hbm.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC 
    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="domain" >
	<class name="Sons" table="sons" >
		<id name="id">
			<generator class="uuid"></generator>
		</id>
		<property name="name" column="name" ></property>
		
        <!--
            name:"一"的那一方的数据成员的名称
            colume:"多"的那一方的表中的外键名
            class:"一"的那一方的类名
        -->
		<many-to-one name="father" column="fatherid" class="Fathers"></many-to-one>
	</class>
</hibernate-mapping>

在father的配置文件中,有个invers反转控制的配置,在hibernate中,每个实体都要维护他本书对应的那张数据表,外键把两张表(两个实体)联系了起来,所以两个实体在维护两张表时可能会出现重复的操作.可以理解为每一个实体类都会维护它本身和属于他本身的外键.所以father每次都要检查一下sons表中的外键是否正确,而且sons还会自己检查一遍表中外键是否正确,所以导致外键被检查了多次,发生了重复维护的情况.invers配置配置为true则说明father这个实体不在对sons中的这个外键进行维护(因为还有sons在维护,所以不用担心没人维护).这样减少了多余重复的检查操作.

注:invers配置在一对多中可以理解为是提高效率的配置,不是必须的,而且在配置invers时一定要保证有一方能维护外键.

测试

    @Test
    public void test1(){
        Configuration cf = new Configuration().configure();
        SessionFactory sf = cf.buildSessionFactory();
        Session session = sf.openSession();
        Transaction transaction = session.beginTransaction();
        //创建对象
        Fathers fathers = new Fathers();
        fathers.setUsername("老王");
        Sons s1 = new Sons();
        Sons s2 = new Sons();
        s1.setName("张三");
        s2.setName("李四");
        //相互为实体对象中添加信息
        fathers.getSons().add(s1);
        fathers.getSons().add(s2);
        s1.setFather(fathers);
        s2.setFather(fathers);
        //保存操作
        session.save(fathers);
        session.save(s1);
        session.save(s2);
        transaction.commit();
        session.close();
    }

 

多对多

这里假设我们有一组模型是老师和学生模型,一个老师可以有多个学生,一个学生有多个老师

java实体类

public class Student implements Serializable {

    private String id;
    private String name;
    Set<Teacher> tealist = new HashSet<Teacher>();

    set/get...
}
public class Teacher implements Serializable{

    private String tid;
    private String name;
    private Set<Student> stulist = new HashSet<Student>();

    set/get..
}

在多对多中每个实体中都要对方的set.

配置文件

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC 
    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
   <!-- 配置表与实体对象的关系 -->
   <!-- package属性:填写一个包名.在元素内部凡是需要书写完整类名的属性,可以直接写简答类名了. -->
<hibernate-mapping package="domain" >
	<class name="Student" table="student" >
		<id name="id">
			<generator class="uuid"></generator>
		</id>
		<property name="name" column="name" ></property>
        <!--
            name:自己类中的set名称
            table:新生成的表名
            key-colume:新表中自己的外键
            class:多对多对方的类名
            many-to-many-colume:新表中对方的外键
        -->
		<set name="tealist" table="grade" inverse="true">
			<key column="id"></key>
			<many-to-many class="Teacher" column="tid"></many-to-many>
		</set>
	</class>
</hibernate-mapping>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC 
    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
   <!-- 配置表与实体对象的关系 -->
   <!-- package属性:填写一个包名.在元素内部凡是需要书写完整类名的属性,可以直接写简答类名了. -->
<hibernate-mapping package="domain" >
	<class name="Teacher" table="teacher" >
		<id name="tid">
			<generator class="uuid"></generator>
		</id>
		<property name="name" column="name" ></property>

         <!--
            name:自己类中的set名称
            table:新生成的表名
            key-colume:新表中自己的外键
            class:多对多对方的类名
            many-to-many-colume:新表中对方的外键
        -->
		<set name="stulist" table="grade">
			<key column="tid"></key>
			<many-to-many class="Student" column="id"></many-to-many>
		</set>
	</class>
</hibernate-mapping>

配置方法是一样的.在多对多的情况中,invers反转控制是必须要配置的.在一对多中,维护外键的方式是检查另一张表中的外键信息,在多对多中不同,两张表有多对多关系时,通常会再创建一张新的表去描述多对多的关系,这时维护外键的方法就变成想这个新表中插入相应的外键记录了,所以当两张表都去维护外键时,就会发生同一条数据被插入两次的情况,这时数据库就会报错,所以这多对多的两张表肯定要有一方放弃外键的维护工作(invers=true).具体哪一方放弃就要看业务逻辑了.

测试

 @Test
    public void test2(){
        Configuration cf = new Configuration().configure();
        SessionFactory sf = cf.buildSessionFactory();
        Session session = sf.openSession();
        Transaction transaction = session.beginTransaction();

        Teacher t1 = new Teacher();
        t1.setName("小明");
        Teacher t2 = new Teacher();
        t2.setName("小白");
        Student s1 = new Student();
        s1.setName("张三");
        Student s2 = new Student();
        s2.setName("李四");
        //向teacher中添加student的信息
        t1.getStulist().add(s1);
        t1.getStulist().add(s2);
        t2.getStulist().add(s1);
        t2.getStulist().add(s2);
        //向student中添加teacher信息
        s1.getTealist().add(t1);
        s1.getTealist().add(t2);
        s2.getTealist().add(t1);
        s2.getTealist().add(t2);
        //保存数据
        session.save(t1);
        session.save(t2);
        session.save(s1);
        session.save(s2);

        transaction.commit();
        session.close();
    }

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值