1. Two-way primary key association
Bidirectional primary key association is actually a special case of one-to-one primary key association. However, <one-to-one> configuration must be performed in the mapping files at both ends of the associated object, and in addition, foreign foreign key association attribute must be used at one end of the primary key of the main map.
Here we also use Person and IdCard to discuss. A person corresponds to a unique ID card, and an ID card also uniquely maps a person, so this creates a two-way association relationship. Person's primary key is also the primary key of IdCard, which are both primary keys and foreign keys. This association relationship becomes a two-way one-to-one mapping, which can be expressed in the relationship model as shown below:
The two tables in the figure use primary key association. The primary key of person is the primary key of idCard, so they form a constraint relationship between Zhu foreign keys, and ensure uniqueness, map it into the object model, and transform it into a one-to-one relationship between person class and idCard class, as shown in the figure below:
This one-to-one relationship also mentioned in the previous article that the <one-to-one> tag is used, and this one-to-one mapping is bidirectional, so we need to configure <one-to-one> between two objects at the same time. First, let’s look at the class code and mapping file code corresponding to idCard.
1. Information corresponding to IdCard
There is a one-to-one relationship between the IdCard.java class, the IdCard class and the Person class. Therefore, the corresponding Person attribute should be added to the IdCard class. This is to add the corresponding attributes to the foreign keys in the mapping file and set the corresponding foreign key association class.
package com.src.hibernate; public class IdCard { //id attribute private int id; public int getId() { return id; } public void setId(int id) { this.id = id; } //card number attribute private String cardNo; public String getCardNo() { return cardNo; } public void setCardNo(String cardNo) { this.cardNo = cardNo; } //People corresponding to card number private Person person; public Person getPerson(){ return person; } public void setPerson(Person person){ this.person=person; } }The IdCard.hbm.xml mapping file adds a foreign key attribute person to the mapping file and adds the corresponding <one-to-one> tag. The purpose is to force constraint person class to achieve a one-to-one mapping relationship. Finally, set the constrained attribute to true in the mapping to ensure the forced constraint relationship.
<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <!-- Generated 2014-5-15 23:47:00 by Hibernate Tools 3.4.0.CR1 --> <hibernate-mapping> <class name="com.src.hibernate.IdCard" table="IDCARD"> <id name="id" type="int" column="personId"> <generator> <param name="property">person</param> </generator> </id> <property name="cardNo" type="string" column="cardno"></property> <one-to-one name="person" constrained="true"></one-to-one> </class> </hibernate-mapping>
2. Person corresponding information
In the Person.java class, in addition to adding basic attributes, the corresponding IdCard class must be added as attributes, because they are a one-to-one two-way association relationship, so the IdCard class must also be added to the Person class. The same reason is that the Person class attributes are also added to the IdCard class.
package com.src.hibernate; public class Person { //id number private int id; public int getId() { return id; } public void setId(int id) { this.id = id; } //name private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } //idCard private IdCard idcard; public IdCard getIdcard() { return idcard; } public void setIdcard(IdCard idcard) { this.idcard = idcard; } }Person.hbm.xml mapping file, the primary key generation strategy in this file has no special requirements because it is mutually restricted by the IdCard class. Its primary key and foreign key are both the primary key of IdCard. In addition, because it is a one-to-one relationship, the <one-to-one> tag should be added to the mapping file to indicate it.
<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <!-- Generated 2014-5-15 23:47:00 by Hibernate Tools 3.4.0.CR1 --> <hibernate-mapping> <class name="com.src.hibernate.Person" table="PERSON"> <id name="id" type="int" column="personId"> <generator></generator> </id> <property name="name" type="string" column="personName"></property> <!-- one-to-one tag indicates how Hibernate loads its associated object. By default, it loads according to the primary key, that is, gets the value of the relationship field and loads the associated object according to the primary key of the opponent--> <one-to-one name="idcard"></one-to-one> </class> </hibernate-mapping>
3. Hibernate mapping file
After the above class and mapping file are configured, the information about the database mapping in Hibernate.cfg.xml is required to add two configuration files to the Hibernate configuration file, so that the corresponding generation items can be found when generating the corresponding database.
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd"> <hibernate-configuration> <session-factory> <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property> <property name="hibernate.connection.url">jdbc:mysql://localhost:3306/hibernate_one2one_pk1</property> <property name="hibernate.connection.username">root</property> <property name="hibernate.connection.password">1234</property> <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property> <mapping resource="com/src/hibernate/Person.hbm.xml"/> <mapping resource="com/src/hibernate/IdCard.hbm.xml" ></mapping> </session-factory> </hibernate-configuration>
4. Generate results
After the configuration is completed, you can generate the corresponding database from the above content. In the database, it will generate the corresponding table structure according to the configured content, and there are corresponding foreign keys and primary key fields in the table. When generating the table structure, Hibernate will output the corresponding SQL statement in the console, as follows:
alter table IDCARD drop foreign key FK806F76ABAC038CD8 drop table if exists IDCARD drop table if exists PERSON create table IDCARD (personId integer not null, cardno varchar(255), primary key (personId)) create table PERSON (personId integer not null auto_increment, personName varchar(255), primary key (personId)) alter table IDCARD add index FK806F76ABAC038CD8 (personId), add constraint FK806F76ABAC038CD8 foreign key (personId) references PERSON (personId)
The generated table structure is as shown in the figure:
The personId primary key is generated in both tables at the same time, and it is also the corresponding foreign key. It also restricts the primary keys of the two tables at the same time and is unique.
5. Write and load test
After generating the table, write the table and read data from the table, write the corresponding test class, and the test uses unit tests and writes the corresponding test methods.
5.1 Write test
When writing to the database, be sure to note that both objects written must be converted to the corresponding Trainent state, otherwise a state conversion error will occur. The test code is as follows:
public void testSave1(){ Session session=null; try{ //Create a session object session=HibernateUtils.getSession(); //Enable session transaction session.beginTransaction(); //Create a person object and save Person person=new Person(); person.setName("zhangsan"); session.save(person); //Create an idCard object and save IdCard idcard=new IdCard(); idcard.setCardNo("1111111111111"); idcard.setPerson(person); session.save(idcard); //Submit transactions and modify the database session.getTransaction().commit(); }catch(Exception e){ //Print error message e.printStackTrace(); //Business rollback session.getTransaction().rollback(); } finally{ //Close the session HibernateUtils.closeSession(session); } } The inserted data is shown below:
5.2 Loading test
Write a loading method. Because the association relationship is bidirectional, the corresponding loading operation should be to load the other end through one end, that is, to obtain the corresponding Person class, and obtain the corresponding IdCard information through the Person class. The opposite should also be true, the code is as follows:
public void testLoad1(){ Session session=null; try{ //Create a session object session=HibernateUtils.getSession(); //Enable session transaction session.beginTransaction(); //Get the person object and save Person person=(Person)session.load(Person.class,5); System.out.println("IdCard.Id: "+person.getIdcard().getId()); System.out.println("IdCard.cardno: "+person.getIdcard().getCardNo()); //Create an idCard object and save IdCard idcard=(IdCard)session.load(IdCard.class, 5); System.out.println("Person.Id: "+idcard.getPerson().getId()); System.out.println("Person.name: "+idcard.getPerson().getName()); //Submit transactions and modify database session.getTransaction().commit(); }catch(Exception e){ //Print error message e.printStackTrace(); //Business rollback session.getTransaction().rollback(); } finally{ //Close the session HibernateUtils.closeSession(session); } } Run the above test method and print the relevant contents on the console as follows:
2. Two-way foreign key relationship
Bidirectional foreign key association can be understood as a special case of foreign key association. This speciality is mainly because it is a bidirectional correspondence. In the previous article, it was mentioned that if you want to add a foreign key field to a table, you can use the <many-to-one> tag, which will generate the corresponding foreign key column in the relationship model. This tag must be used if you want to achieve two-way foreign key association.
1. Object Model
Let’s first look at the object model. People and ID cards are a one-to-one relationship. One person corresponds to an identity, so the multiplexes between them are one-to-one, and this correspondence is two-way. Therefore, its object model is the same as the bidirectional primary key one-to-one, as shown in the figure below:
2. Relational model
The corresponding relationship model will change greatly. The one-to-one foreign key relationship will generate the corresponding foreign key in a table. When you get the person and the ID card, it means that there will be a primary key column of the ID card number in the relationship model, and a two-way one-to-one situation is formed between them, as shown in the figure below:
The correspondence between them is as seen in the figure above. There is the primary key of the idCard table in the person table, forming a one-to-one foreign key association relationship, and it is bidirectional. That is to say, the idCard can be obtained through person, and the person can also be obtained through idCard.
The code in the Person object and the IdCard object is the same as the object code in the previous article. It is not listed in the code. The only difference is the configuration problem in the mapping file.
3. Mapping files
idCard.hbm.xml mapping file. The idCard table is not the main table of the mapping, so when doing one-to-one mapping, you need to use the <one-to-one> tag to configure it, and you need to formulate foreign key attributes in the person relationship model. 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"> <!-- Generated 2014-5-18 22:27:43 by Hibernate Tools 3.4.0.CR1 --> <hibernate-mapping> <class name="com.src.hibernate.IdCard" table="IDCARD"> <id name="id" type="int"> <generator /> </id> <property name="cardNo" type="java.lang.String"> <column name="CARDNO" /> </property> <one-to-one name="person" property-ref="idCard"></one-to-one> </class> </hibernate-mapping>
Person.hbm.xml mapping file, the person table is the main table of the mapping. A foreign key attribute column needs to be added to the table to indicate the idCard table. Therefore, the <many-to-one> tag needs to be used here to generate the corresponding foreign key in the person object, and unique must also use unique to indicate that the attribute is unique.
<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <!-- Generated 2014-5-18 22:27:43 by Hibernate Tools 3.4.0.CR1 --> <hibernate-mapping> <class name="com.src.hibernate.Person" table="PERSON"> <id name="id" type="int" column="personId"> <generator /> </id> <property name="name" type="java.lang.String"> <column name="NAME" /> </property> <many-to-one name="idCard" column="idCardNo" unique="true" not-null="true"></many-to-one> </class> </hibernate-mapping>
The mapping file configuration of the object is completed, and then a relational model is generated. The SQL statement is as follows:
alter table PERSON drop foreign key FK8C768F55794A52CA drop table if exists IDCARD drop table if exists PERSON create table IDCARD (id integer not null auto_increment, CARDNO varchar(255), primary key (id)) create table PERSON (personId integer not null auto_increment, NAME varchar(255), idCardNo integer not null unique, primary key (personId)) alter table PERSON add index FK8C768F55794A52CA (idCardNo), add constraint FK8C768F55794A52CA foreign key (idCardNo) references IDCARD (id)
The generated SQL statement is first of all the created table. When creating the table, the primary key column is specified. After the creation is completed, the two tables are modified to specify foreign key attributes to form a one-to-one relationship.
Write a test method, adopt unit tests, load objects of two classes, and obtain another object from one end of the object respectively
//Load the object and load the person object using the IdCard object public void testLoad1(){ Session session=null; try{ session=HibernateUtils.getSession(); session.beginTransaction(); //Get the IdCard object and get the person object uniquely associated with the object in IdCard IdCard idcard=(IdCard)session.load(IdCard.class,1); System.out.println("person.Id= "+idcard.getPerson().getId()); System.out.println("idCard.person.name= "+idcard.getPerson().getName()); //GetPerson object and get the IdCard object that is uniquely associated with it in the Person object Person person=(Person)session.load(Person.class,1); System.out.println("idCard.id: "+person.getIdCard().getId()); System.out.println("idCard.cardNo: "+person.getIdCard().getCardNo()); //Commit transaction session.getTransaction().commit(); }catch(Exception e){ e.printStackTrace(); session.getTransaction().rollback(); } finally{ HibernateUtils.closeSession(session); } } Generated content:
Comparing the two mapping relationships, the primary key and foreign key mapping relationships are both bidirectional mapping relationships, and the mapping relationship needs to be configured at the same time at both ends of the object. The difference is that the primary key only needs to use <one-to-one> because it does not need to generate attribute columns, but the foreign primary key generation strategy must be used for the primary key of the table and the foreign key object is marked; the foreign key generation strategy needs to use the <many-to-one> tag to generate new foreign key columns.
Conclusion
The one-to-one mapping in a two-way association has been discussed so far. The two articles mainly discuss two uses of a two-way association. In fact, it is still very simple. Remember to use the <many-to-one> tag if you want to generate a foreign key. If it is unique, add the unique attribute. The <one-to-one> tag only indicates a one-to-one relationship. It only indicates how one object loads another object and does not add a new column in the relationship model. The next article will discuss one-to-many relationships.