Storing one to many object relationships using Hibernate

Keywords: Session Hibernate Database xml

There are often relationships between objects in life, such as one-to-one, one to many, many to many. For example, there are many students in a Course class who are one to many. In the database, you can add a foreign key to the Student table to point to the class id to indicate that the Student contains multiple Student relationships. Correspondingly, in Java, you can create two classes, Course and Student, to represent the class and Student. How to establish the relationship between them?

The courses table and students table in the database are as follows

   

One to many mapping

The first is a one to many mapping, such as establishing a mapping from a class ("one") to a Student ("many"). You can add a Set collection in the Course class to hold multiple Student objects, and Set Course to point to Student in hibernate.

Add Hibernate database mapping to the two classes in IDEA, the CourseEntity class, StudentEntity class file and corresponding hbm.xml mapping file will be generated automatically, and registration will be completed in hibernate.cfg.xml file. Then manually add the Set attribute students and its get/set method in CourseEntity

public class CoursesEntity {
    private int id;
    private String name;
    private Integer hours;
    private Set<StudentEntity> students=new HashSet<StudentEntity>();
    
    ......

    public Set<StudentEntity> getStudents() {
        return students;
    }

    public void setStudents(Set<StudentEntity> students) {
        this.students = students;
    }

Then you need to modify the CourseEntity.hbm.xml file, add the set attribute students, specify the corresponding data table and the foreign key associated with the data table courses, as well as the Java entity class corresponding to the attribute

    <class name="entity.CoursesEntity" table="courses" schema="test">
        <id name="id" column="id"/>
        <property name="name" column="name"/>
        <property name="hours" column="hours"/>
        <set name="students" table="students">              <!--To configure students Table corresponding to set-->
            <key column="course_id"></key>                  <!--Corresponding foreign key in the table-->
            <one-to-many class="entity.StudentEntity"/>     <!--Corresponding Java class-->
        </set>
    </class>

After that, create a course course object in the test method, and two student objects s1 and s2, and call add() of Set in the students collection of the course to add two student objects, and finally save these objects in the database. Note that Junit test unit is still used here, so the creation and shutdown of session and factory are completed in previous setup and tearDown.

    @Test
    void testCourse(){
        //Create course and student objects
        CoursesEntity course=new CoursesEntity(2,"Data Structure",72);
        StudentEntity s1=new StudentEntity(1003,"Xiao Ming",15);
        StudentEntity s2=new StudentEntity(1004,"Floret",14);
        //Add two student objects to the Set set of students in the course
        course.getStudents().add(s1);
        course.getStudents().add(s2);
        //Save course and student objects to database
        session.save(course);
        session.save(s1);
        session.save(s2);
    }

Viewing the database, it can be seen that the corresponding courses have been added in the course table, and not only two students have been added in the students table, but also their foreign key course ﹣ id points to the corresponding course id

   

It is also very convenient to view the data. You can traverse the selected students through the Set set returned by course, and hibernate will automatically retrieve the corresponding student information from the students table

     @Test
    void findCourse() {
        CoursesEntity course = session.load(CoursesEntity.class, 2);
        System.out.println("Course Name:"+course.getName());
        //Return student Set set through course to traverse student information
        Set<StudentEntity> students = course.getStudents();
        System.out.println("Course students:");
        for (StudentEntity student : students)
            System.out.print(student.getId() + ':' + student.getName());
    }

Delete a student from the course. By calling the remove() method of Set, the database will automatically change the foreign key of the student course ﹣ ID to null

CoursesEntity course = session.load(CoursesEntity.class, 2);
Set<StudentEntity> students = course.getStudents();            //Get the Set set of course students
StudentEntity s=session.load(StudentEntity.class,1003);        //Get the specified Student object
//Delete the specified student from the course selection list
students.remove(s);         
session.save(s);        //Save operation

Bidirectional mapping

In addition to configuring the Course to Student mapping, you can also configure the Student to Course mapping. This enables two-way mapping between two object types. Map Student - > Course as follows:

First, add the variable course and get/set method to the StudentEntity class to represent the course property

public class StudentEntity {
    private int id;
    private String name;
    private Integer age;
    private Address address;
    private CoursesEntity course;    //Add attribute representing the course
    
    ......

    public CoursesEntity getCourse() {
        return course;
    }

    public void setCourse(CoursesEntity course) {
        this.course = course;
    }

Then configure the "multi" hbm.xml file, with name as the variable name, class as the pointed class, and column as the foreign key in the data table

    <class name="entity.StudentEntity" table="students" schema="test">
        <id name="id" column="id"/>
        <property name="name" column="Name"/>
        <property name="age" column="Age"/>
        <component name="address" class="entity.Address">
            <property name="city" column="city"/>
            <property name="street" column="street"/>
        </component>
        <!--To configure Student point Course Mapping-->
        <many-to-one name="course" class="entity.CoursesEntity" column="course_id"/>
    </class>

Next, create the Course and Student objects in the code and map them in two directions

    @Test
    void testCourse() {
        //Create course and student objects
        CoursesEntity course = new CoursesEntity(2, "Data Structure", 72);
        StudentEntity s1 = new StudentEntity(1003, "Xiao Ming", 15);
        StudentEntity s2 = new StudentEntity(1004, "Floret", 14);

        //Add course - > student mapping
        course.getStudents().add(s1);
        course.getStudents().add(s2);
        //Add student - > Course mapping
        s1.setCourse(course);
        s2.setCourse(course);

        //Save course and student objects to database
        session.save(course);
        session.save(s1);
        session.save(s2);
    }

Maintain bi-directional mapping: through the above operations, the bi-directional mapping of the data table is realized, but look at the HIbernate execution statement as shown below. After two insert operations of the students table, two update operations are performed. This is because the force insert operation is performed when Course maintains the one to many relationship, and then the update operation is performed when student maintains the many to one relationship, which is unnecessary and affects the execution efficiency. It is obvious that this is because both parties are maintaining one to many relationships. Therefore, we want only one party to maintain one to many relationships. In the Course configuration file, set the inverse property of set to false, which means that the relationship is maintained by the "many" party.

Hibernate: insert into courses (name, hours, id) values (?, ?, ?)
Hibernate: insert into students (Name, Age, city, street, course_id, id) values (?, ?, ?, ?, ?, ?)
Hibernate: insert into students (Name, Age, city, street, course_id, id) values (?, ?, ?, ?, ?, ?)
Hibernate: update students set course_id=? where id=?
Hibernate: update students set course_id=? where id=?

Cascade operation: when saving objects through session, we not only execute session.save(course), but also execute session.save(s1) to save students. The Course object already contains students, which should be saved together automatically instead of manually saving. This requires cascade operation to set. You can configure the set in the Course configuration file, and set the cascade property as follows

Set inverse and cascade as follows:

    <class name="entity.CoursesEntity" table="courses" schema="test">
        <id name="id" column="id"/>
        <property name="name" column="name"/>
        <property name="hours" column="hours"/>
        <!--Yes inverse,cascade Property to set-->
        <set name="students" table="students" inverse="false" cascade="save-update">
            <key column="course_id"></key> 
            <one-to-many class="entity.StudentEntity"/>
        </set>
    </class>
112 original articles published, 47 praised, 120000 visitors+
Private letter follow

Posted by monkuar on Thu, 27 Feb 2020 03:24:00 -0800