As an ORM framework, hibernate must also meet our needs to implement the association between tables. The implementation of hibernate in the association method is very simple. Let’s take a look at one-on-one approach:
Without further ado, let's just upload the code:
Two entity classes, TUser and TPassport:
public class TUser implements Serializable{ private static final long serialVersionUID = 1L; private int id; private int age; private String name; private TPassport passport; //Omit Get/Set method} public class TPassport implements Serializable{ private static final long serialVersionUID = 1L; private int id; private String serial; private int expiry; private TUser user; //Omit Get/Set method}Let's take a look at the differences between mapping files:
<hibernate-mapping package="org.hibernate.tutorial.domain4"> <class name="TUser" table="USER4"> <id name="id" column="id"> <generator /> </id> <property name="name" type="java.lang.String" column="name"/> <property name="age" type="java.lang.Integer" column="age"/> <one-to-one name="passport" cascade="all" outer-join="true" /> </class> </hibernate-mapping>
Here we see a new label, one-to-one, which shows that the current class and the corresponding class are one-to-one, and the cascade is a cascade relationship. All indicates that the cascade is performed in any case, that is, when operating on the TUser class, TPassport will also perform corresponding operations. outer-join refers to whether to use the outer join statement.
Let's look at another TPassport mapping file:
<hibernate-mapping package="org.hibernate.tutorial.domain4"> <class name="TPassport" table="passport4"> <id name="id" column="id"> <generator > <param name="property">user</param> </generator> </id> <property name="serial" type="java.lang.String" column="serial"/> <property name="expiry" type="java.lang.Integer" column="expiry"/> <one-to-one name="user" constrained="true" /> </class> </hibernate-mapping>
Here we focus on the class value of generator. It indicates the reference foreign key for foreign, and which reference is specified by param, which indicates the id of the reference User class. There is an additional constrained property in the one-to-one tag, which tells hibernate that there is a foreign key constraint in the current class, that is, the ID of the current class is generated based on the ID of the TUser.
Let's directly upload the test class. This time, the test class did not use JUnit but directly came with Main method:
public static void main(String[] args) { Configuration cfg = new Configuration().configure(); SessionFactory sessionFactory = cfg.buildSessionFactory(); Session session = sessionFactory.openSession(); session.beginTransaction(); TUser user = new TUser(); user.setAge(20); user.setName("shunTest"); TPassport passport = new TPassport(); passport.setExpiry(20); passport.setSerial("123123123"); passport.setUser(user); user.setPassport(passport); session.save(user); session.getTransaction().commit(); }The code is very simple, so I won't talk about it. Let's look at it mainly here:
session.save(user);
Why do we only call one save here? The reason is that the cascade property in our TUser mapping file is set to all, which means that when we save, update, delete, etc. on the TUser, TPassport will also perform corresponding operations, so we do not need to write session.save(passport). We see the background:
Hibernate: insert into USER4 (name, age) values (?, ?) Hibernate: insert into passport4 (serial, expiry, id) values (?, ?, ?)Hibernate: It prints out two statements, proving that hibernate has done this work for us.
public static void main(String[] args) { Configuration cfg = new Configuration().configure(); SessionFactory sessionFactory = cfg.buildSessionFactory(); Session session = sessionFactory.openSession(); TUser user = (TUser)session.load(TUser.class,new Integer(3)); System.out.println(user.getName()+":"+user.getPassport().getSerial()); } Here we query the TUser class and get the TPassport object. Foreign key association
Now let’s take a look at one-to-one associations that make associations through foreign keys.
It is still the same as the example: we wrote two entity classes, TGroup and TUser
public class TGroup implements Serializable{ private static final long serialVersionUID = 1L; private int id; private String name; private TUser user; //Omit Get/Set method} public class TUser implements Serializable{ private static final long serialVersionUID = 1L; private int id; private int age; private String name; private TGroup group; //Omit Get/Set method} After the entity class is finished, let’s take a look at the mapping file:
<hibernate-mapping package="org.hibernate.tutorial.domain5"> <class name="TUser" table="USER5"> <id name="id" column="id"> <generator /> </id> <property name="name" type="java.lang.String" column="name"/> <property name="age" type="java.lang.Integer" column="age"/> <many-to-one name="group" column="group_id" unique="true" /> </class> </hibernate-mapping>
Here we see that the many-to-one tag is used instead of one-to-one. Why?
I didn't pay much attention to it when I used it before. Anyway, I just need to use it. But after reading Xia Xin's book this time, I finally understood that in fact, this way of association through foreign keys is just a special way of many-to-one. We limited it through unique="true" that it must have only one, that is, one-to-one correlation.
Next, let's take a look at the mapping file of TGroup:
<hibernate-mapping package="org.hibernate.tutorial.domain5"> <class name="TGroup" table="group5"> <id name="id" column="id"> <generator /> </id> <property name="name" type="java.lang.String" column="name"/> <one-to-one name="user" property-ref="group" /> </class> </hibernate-mapping>
Here, note that we use one-to-one again, indicating that the current entity and TUser are one-to-one. Here, we do not use many-to-one, but specify which attribute in the TUser entity to associate the current class TGroup. Here we specify that TUser is associated with Tuser through group attributes. property-ref specifies which property to associate.
Let's look at the test class below:
public class HibernateTest { public static void main(String[] args) { Configuration cfg = new Configuration().configure(); SessionFactory sessionFactory = cfg.buildSessionFactory(); Session session = sessionFactory.openSession(); session.beginTransaction(); TGroup group = new TGroup(); group.setName("testGroup"); TUser user = new TUser(); user.setAge(23); user.setName("test"); user.setGroup(group); group.setUser(user); session.save(group); session.save(user); session.getTransaction().commit(); session.close(); } } Note that our code needs to be saved twice this time because they have corresponding correspondences for each other. Saving only one will not cause any operation on the other. So we need to call the saved operation twice. Finally make a submission.
hibernate prints out the statement:
Hibernate: insert into group5 (name) values (?) Hibernate: insert into USER5 (name, age, group_id) values (?, ?, ?)
This means that we correctly stored two object values.
We write an extra test class to query:
public static void main(String[] args) { Configuration cfg = new Configuration().configure(); SessionFactory sessionFactory = cfg.buildSessionFactory(); Session session = sessionFactory.openSession(); TUser user = (TUser)session.load(TUser.class,new Integer(1)); System.out.println("From User get Group:"+user.getGroup().getName()); TGroup group = (TGroup)session.load(TGroup.class,new Integer(1)); System.out.println("From Group get User:" + group.getUser().getName()); session.close(); } We can both get the correct result, which shows that we can take out the other's values through two objects, achieving our goal.
The TGroup and TUser used in this example are just examples. In fact, users in real life generally correspond to multiple groups.