一对多的单项关联

现在我们来讨论一下一对多的单项关联。
首先把环境搭好。
我们就拿老生常谈的班级和学生作为例子。
关于班级类:有班级的id ,班级的名字,班级的描述。
关于学生类:有学生的id,学生的名字,学生的描述。
首先两张表要进行关联,首先需要外键,那么在一对多的情况中,外键是放在多的那一方。(外键在多的那一方是指生成的表在数据库中,外键在多的那一方)
首先我们要把2个类设计出来。
classes:

    private Long cid;
    private String cname;
    private String cdescription;
    //关于这里为什么用set,因为学生尽量不要重复,为了保证唯一性,所以用set
    private Set<Student> students;
    //在这里省略getter&setter

student:

    private Long sid;
    private String sname;
    private String sdescription;
    //同样在这里胜率setter&getter

然后就是配置文件,这里有2个domain,所以也要有2个映射文件/
首先是classes的

<class name="cn.ansel.domain.Classes">
        <id name="cid" length="55">
            <generator class="increment"></generator>
        </id>
        <property name="cname" length="55"></property>
        <property name="cdescription" length="111"></property>
        <!-- 

            name:对于classes中的students
            key:表示外键的名字
            one-to-many:表示对应多的那一方的类的全名
         -->
        <set name="students">
            <key column="cid"></key>
            <one-to-many class="cn.ansel.domain.Student"/>
        </set>
    </class>

然后是student

    <class name="cn.ansel.domain.Student">
        <id name="sid" length="11">
            <generator class="increment"></generator>       
        </id>
        <property name="sname" length="11"></property>
        <property name="sdescription" length="111"></property>
    </class>

在Student类及配置文件中,都没有看到可以找到与classes关联的属性,这叫做单向关联,然后我们创建一个测试类,来生成表:


public class testCreateTable extends hibernateUtil {
    @Test
    public void createTable(){

    }
}

最后,一定要记得,把2个映射文件都加到hibernate的配置文件中。
最后在数据库中,我们可以看到两张表,并且点开表之后,可以看到里面的属性,外键。
这里写图片描述


例子:
保存班级:

public void testSave_Classes(){
        Session session=sessionFactory.openSession();
        Transaction transaction=session.beginTransaction();

        Classes classes=new Classes();
        classes.setCdescription("nice");
        classes.setCname("rocket");

        session.save(classes);

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

运行结果如下图所示
这里写图片描述

保存学生:

    public void testSave_Student(){
        Session session=sessionFactory.openSession();
        Transaction transaction=session.beginTransaction();

        Student student=new Student();
        student.setSdescription("nice");
        student.setSname("ansel");

        session.save(student);

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

运行结果如下图
这里写图片描述
在这里可以注意到,cid是没有值的!

保存学生和班级

@Test
    public void testSaveClasses_Student(){
        Session session=sessionFactory.openSession();
        Transaction transaction=session.beginTransaction();
        //新建班级
        Classes classes=new Classes();
        classes.setCdescription("exciting");
        classes.setCname("subway");
        //新建学生
        Student student=new Student();
        student.setSdescription("so-so");
        student.setSname("andy");
        //新建存储学生的集合
        Set<Student> students=new HashSet<Student>();
        students.add(student);
        //从班级中取出集合,并把创建的集合存到里面
        classes.setStudents(students);
        //分别保存
        session.save(student);
        session.save(classes);

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

操作结果如下:
student表:
这里写图片描述

classes表:
这里写图片描述

可是这样保存两次,太麻烦,hibernate推出了级联操作,在保存一个有关联的对象的时候,跟这个对象关联的对象也会被保存。

级联操作:
在映射文件中的set属性,增加一个属性cascade

<!-- 
    save-update:在保存关联的一方操作时,检查另外一方对象是否需要保存/更新
    inverse:取值有true/false/default,其中true表示不维护该类与主键的关系,如果不维护,那么student表的cid的值会为null,要想该属性起作用,必须有2要求:
    1、inverse的值为false/default
    2、在客户端中必须声明关联类的关系,否则也是不起作用的
-->
<set name="students" cascade="save-update" inverse="false">
            <key column="cid"></key>
            <one-to-many class="cn.ansel.domain.Student"/>
        </set>

那么在保存班级的同时,保存学生:

public void testCascade(){
        Session session=sessionFactory.openSession();
        Transaction transaction=session.beginTransaction();
        //新建班级
        Classes classes=new Classes();
        classes.setCdescription("healthy");
        classes.setCname("PE");
        //新建学生
        Student student=new Student();
        student.setSdescription("possitive");
        student.setSname("jone");
        //新建存储学生的集合
        Set<Student> students=new HashSet<Student>();
        students.add(student);
        //从班级中取出集合,并把创建的集合存到里面
        classes.setStudents(students);
        //这里只保存了班级
        session.save(classes);

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

运行结果:
这里写图片描述
student表
这里写图片描述
classes表
这里写图片描述

这种操作又叫做隐式操作。
如果在映射文件中没有设置cascade属性,就会报错。
这里写图片描述
为什么会报这样的错误呢?
因为看我们的代码可以知道,我们只是保存了classes,但是此时,student还是处于瞬时状态的对象,由于没有设置级联的属性,所以就报对象参照了一个没有保存的瞬时对象的错误。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值