一对多的单项关联

来源:互联网 发布:淘宝怎查被隐形降权 编辑:程序博客网 时间:2024/04/29 16:11

现在我们来讨论一下一对多的单项关联。
首先把环境搭好。
我们就拿老生常谈的班级和学生作为例子。
关于班级类:有班级的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还是处于瞬时状态的对象,由于没有设置级联的属性,所以就报对象参照了一个没有保存的瞬时对象的错误。

0 0
原创粉丝点击