1. One-to-many one-way association mapping
The object model of one-to-many relationship is often seen in daily life. Take students and classes as an example. There are multiple students in a class, so the relationship between the class and students is a one-to-many relationship, mapped into the object model, as shown in the figure below:
The object model shows that this one-to-many relationship is maintained by one end, so the mapping into a relationship model means that there will be multiple students under a class field, which forms a one-to-many relationship. Student information can be obtained through the class. The corresponding relationship model is as follows:
1. Basic configuration
With the object model, then map them into corresponding relationship code. When performing relationship mapping, you need to add the <one-to-many> tag on one end. In addition, you need to add the Set attribute on one end. It supports lazy loading, and then add the set tag in the mapping file and specify a one-to-many relationship, so that you can query and get the multiple end on one end.
Classes and mapping files:
It is the most important end of the model. On this end, you need to add the corresponding set attribute and add the set tag in the configuration file. You can configure the corresponding <one-to-many> object in the set tag. The specific Classes.java object code is as follows:
package com.src.hibernate; import java.util.Set; public class Classes { private int id; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } private String name; //Set supports lazy loading of private Set students; public Set getStudents() { return students; } public void setStudents(Set students) { this.students = students; } }The set attribute is used in the Classes object, but it only explains the delayed loading attributes and does not configure the corresponding object for the attribute. The object of the attribute needs to be configured in the mapping file. You need to add a set tag and add the <one-to-many> tag to the set tag. The specific code is as follows:
<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping> <class name="com.hibernate.Classes" table="t_classes"> <id name="id"> <generator//id> <property name="name"/> <set name="students"> <key column="classesid"></key> <one-to-many></one-to-many> </set> </class> </hibernate-mapping>
The code and mapping files in the corresponding Student object do not require any special configuration, they only need to be written according to the usual writing method. The specific configuration method will not be described in detail, it is very simple. After configuration, you need to generate the corresponding SQL statement. When converting the object model into a relational model, Hibernate generates the corresponding statement as follows:
alter table t_student drop foreign key FK4B9075705E0AFEFE drop table if exists t_classes drop table if exists t_student create table t_classes (id integer not null auto_increment, name varchar(255), primary key (id)) create table t_student (id integer not null auto_increment, name varchar(255), classesid integer, primary key (id)) alter table t_student add index FK4B9075705E0AFEFE (classesid), add constraint FK4B9075705E0AFEFE foreign key (classesid) references t_classes (id)
The corresponding relationship model generated is shown below:
Comparing SQL statements and relationship models, the association between corresponding tables is maintained through foreign keys. First, create two tables, specify the primary key of the table, and finally add a one-to-many foreign key association relationship.
2. Basic operations
The operations on the database are nothing more than read and write, and modification is also a type of write. Next, let’s see how to write and read operations into the database.
(1) Write data:
When writing data, you need to pay attention to the one-to-many relationship, so you need to add multiple student classes when adding them. In addition, since the corresponding set attribute is added to the classes, you should use HashSet to add when adding Student objects, so you can realize a one-to-many relationship. The specific code is as follows:
public void testSave2(){ Session session=null; try{ session=HibernateUtils.getSession(); session.beginTransaction(); Student student1=new Student(); student1.setName("zhangsan"); session.save(student1); Student student2=new Student(); student2.setName("lisi"); session.save(student2); Classes classes=new Classes(); classes.setName("ClassOne"); Set students=new HashSet(); students.add(student1); students.add(student2); classes.setStudents(students); //The data can be saved successfully//But an extra update statement will be issued to maintain the relationship because it is one-to-many reason session.save(classes); session.getTransaction().commit(); }catch(Exception e){ e.printStackTrace(); session.getTransaction().rollback(); } finally{ HibernateUtils.closeSession(session); } } Then, after the corresponding data generated by running the above test case is written to the database, the following figure is as follows:
(2) Read data:
The write operation is relatively simple. You only need to add all the loaded objects to the Transient state and run the corresponding method to insert the content. However, the corresponding read operation will be a little more complicated. Because it is necessary to iterate to obtain all student objects, this one-to-many relationship is not very efficient. The specific code is as follows:
package com.test.hibernate; import java.util.Iterator; import java.util.Set; import com.src.hibernate.*; import junit.framework.TestCase; import org.hibernate.Session; public class One2ManyTest extends TestCase { public void testLoad1(){ Session session=null; try{ session=HibernateUtils.getSession(); session.beginTransaction(); //Get class information with primary key 5 Classes classes=(Classes)session.load(Classes.class,5); //Print class information System.out.println("classes.name="+classes.getName()); //Set the student set and load the student set through the class Set students=classes.getStudents(); //Iterate the set and print the student information in the set for(Iterator iter=students.iterator(); iter.hasNext();){ Student student=(Student)iter.next(); System.out.println("student.name="+student.getName()); } session.getTransaction().commit(); }catch(Exception e){ e.printStackTrace(); session.getTransaction().rollback(); } finally{ HibernateUtils.closeSession(session); } } }The corresponding statements and information generated are as follows:
Hibernate: select classes0_.id as id1_0_, classes0_.name as name1_0_ from t_classes classes0_ where classes0_.id=? classes.name=ClassOne Hibernate: select students0_.classesid as classid1_, students0_.id as id1_, students0_.id as id0_0_, students0_.name as name0_0_ from t_student students0_ where students0_.classesid=? student.name=lisi student.name=zhangsan
2. One-to-many bidirectional association mapping
Here we continue to use students and classes as examples. There is a one-to-many relationship between the class and students. There are multiple students in a class. Unlike the previous article, the relationship here is two-way, that is, one end and one end maintain the relationship at the same time, so its object diagram is as follows:
The corresponding relationship model diagram does not change much, because the relationship between them is bidirectional, so both ends of the relationship model maintain the relationship relationship at the same time and map it to the relationship model as shown in the figure below:
In a one-to-many one-way association, the mapping file only needs to be specially configured on one end. Use the <one-to-many> configuration and use the set iterator in the object model to set the outlinked object model. However, the difference is that in a two-way association, the corresponding foreign key association at the other end needs to be added on the multiple end. At this time, the relationship of <many-to-one> must be used on the multiple end to indicate this bidirectionality.
1. Mapping
Classes and Student are also used as examples here. The content on the Classes end is the same as above and will not change, but the configuration of Students on the multiple ends will change, that is, the <many-to-one> tag needs to be added to the mapping file.
The Student.hbm.xml mapping file configuration requires adding a foreign key column <many-to-one> tag, and the name of the column must be consistent with the name of the foreign key column of Classes.hbm.xml. The specific code is as follows:
<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping> <class name="com.src.hibernate.Student" table="t_student"> <id name="id"> <generator/generator/> </id> <property name="name"/> <!-- Add a new Classes column in the Student on one side, and the column name should be the same as the list of Classes.hbm.xml --> <many-to-one name="classes" column="classesid"></many-to-one> </class> </hibernate-mapping>
The configuration of the Classes.hbm.xml mapping file is the same as in the previous article. It should be noted that the set attribute mapping is added to the Classes.java file and corresponds to the Student object. Therefore, the set tag needs to be added to the mapping file to indicate that the set iterator is used in the object model. The specific configuration is as follows:
<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping> <class name="com.src.hibernate.Classes" table="t_classes"> <id name="id"> <generator//id> <property name="name"/> <set name="students" inverse="true"> <key column="classesid"></key> <one-to-many></one-to-many> </set> </class> </hibernate-mapping>
2. Class
The configuration of the mapping file is directly corresponding to the class, so with the mapping file, you can write the corresponding class. With the same class, you can know how to write the corresponding mapping file. Let’s take a look at how to write the corresponding class code.
Student.java class requires adding associated class object attributes to the class, and you can obtain Classes related information when loading Student.
package com.src.hibernate; public class Student { //Associated class object private Classes classes; public Classes getClasses() { return classes; } public void setClasses(Classes classes) { this.classes = classes; } //Student id private int id; public int getId() { return id; } public void setId(int id) { this.id = id; } //Student name private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } } The specific code content of Classes.java file is shown in the previous article, and will not be described in detail here.
With the object model, the relationship model is generated. The generated SQL statement is as follows:
alter table t_student drop foreign key FK4B907570FC588BF4 drop table if exists t_classes drop table if exists t_student create table t_classes (id integer not null auto_increment, name varchar(255), primary key (id)) create table t_student (id integer not null auto_increment, name varchar(255), classesid integer, primary key (id)) alter table t_student add index FK4B907570FC588BF4 (classesid), add constraint FK4B907570FC588BF4 foreign key (classesid) references t_classes (id)
3. Data operation
After establishing a table structure, I wrote a test method to verify the operation of data. First, let’s take a look at the insertion of data and insert data into the table structure. There are two situations when writing data. One is to first create a Classes object, write the object to the database, then create a Student object, and add the student object to the Classes object; the other is to first create a student object, write the student object to the database, and then create a Classes object to add the student object to the Classes object. These two types of operations are different in the end, so let’s compare.
3.1 Write the class first and then write the students
After writing the class to the database first, the Classes object enters the Transient state and has a row in the database. Then write the Student object. The Student object will look for the corresponding Classes primary key and write it to the table. Therefore, the data in the relationship model is non-empty, and the saved code is as follows:
public void testSave(){ Session session=null; try{ //Create session object session=HibernateUtils.getSession(); //Open transaction session.beginTransaction(); //Create class object and write class object to the database Classes classes=new Classes(); classes.setName("class"); session.save(classes); //Create student 1 object and write student object to the database Student student1=new Student(); student1.setName("zhangsan"); student1.setClasses(classes); session.save(student1); //Create Student 2 object and write the student object to the database Student student2=new Student(); student2.setName("lisi"); student2.setClasses(classes); session.save(student2); session.getTransaction().commit(); }catch(Exception e){ e.printStackTrace(); session.getTransaction().rollback(); } finally{ HibernateUtils.closeSession(session); } } The corresponding information list in the write database is as follows:
3.2 Write the students first and then the class
First write the students into the database. At this time, because the student table needs to obtain the primary key information of the corresponding class column, but because the class information is converted to the Transient state, there will be a null value when writing the student information. The code is as follows:
The corresponding database view after writing is as follows:
Comparing the two write operations, different results appear because the order of the two writes is different, but because it is a bidirectional association, no exception occurs during writing.
4. Read operation
Compared with writing data, reading data becomes very simple. Because it is a bidirectional association, the reading of data is also bidirectional. Information from the other end can be read from any end, as shown in the following code:
public void testLoad1(){ Session session=null; try{ session=HibernateUtils.getSession(); session.beginTransaction(); //Read student information through class Classes classes=(Classes)session.load(Classes.class,1); System.out.println("classes.name="+classes.getName()); Set students=classes.getStudents(); for(Iterator iter=students.iterator(); iter.hasNext();){ Student student=(Student)iter.next(); System.out.println("student.name="+student.getName()); } //Read class information through student information Student stu=new Student(); stu=(Student)session.load(Student.class, 1); System.out.println("Load class information through student Classes.id= "+stu.getClasses().getId()); session.getTransaction().commit(); }catch(Exception e){ e.printStackTrace(); session.getTransaction().rollback(); } finally{ HibernateUtils.closeSession(session); } }Run the above test statement and the corresponding statement information generated is as follows:
Hibernate: select classes0_.id as id1_0_, classes0_.name as name1_0_ from t_classes classes0_ where classes0_.id=? classes.name=class Hibernate: select students0_.classesid as classid1_, students0_.id as id1_, students0_.id as id0_0_, students0_.name as name0_0_, students0_.classesid as classid0_0_ from t_student students0_ where students0_.classesid=? student.name=lisi student.name=zhangsan
Loading class information by students Classes.id= 1