One-to-one mapping using foreign key association

In a one-to-one relationship, each row in the first table is linked to exactly one row in another table. If this relationship is applied, we can say that both the tables have an exactly equal number of rows any time.

We will take a look at the unidirectional and bidirectional ways to show a one-to-one relationship between the tables.

Getting ready

Here, we will consider the Person and PersonDetail classes to show a demo. So, let's first create the classes and tables for both.

Creating the tables

Use the following script to create the tables if you are not using hbm2dll=create|update:

Use the following script to create the passport_detail table:

CREATE TABLE `passport_detail` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `passportno` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
);

Use the following script to create the person table:

CREATE TABLE `person` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) DEFAULT NULL,
  `passport_detail_id` bigint(20) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `FK_PERSON_ID` (`passport_detail_id`),
  CONSTRAINT `FK_PERSON_ID` FOREIGN KEY (`passport_detail_id`) REFERENCES `passport_detail` (`id`)
);

Creating the classes

Use the following code to create the classes:

Source file: PassportDetail.java

@Entity
@Table(name = "passport_detail")
public class PassportDetail {

  @Id
  @GeneratedValue
  @Column(name = "id")
  private long id;

  @Column(name = "passportno")
  private String passportNo;

  public long getId() {
    return id;
  }

  public void setId(long id) {
    this.id = id;
  }

  public String getPassportNo() {
    return passportNo;
  }

  public void setPassportNo(String passportNo) {
    this.passportNo = passportNo;
  }

}

Source file: Person.java

@Entity
@Table(name = "person")
public class Person {

  @Id
  @GeneratedValue
  @Column(name = "id")
  private long id;

  @Column(name = "name")
  private String name;

  @OneToOne(cascade = CascadeType.ALL)
  @JoinColumn(name = "passport_detail_id")
  private PassportDetail passportDetail;

  public long getId() {
    return id;
  }

  public void setId(long id) {
    this.id = id;
  }

  public String getName() {
    return name;
  }

  public void setName(String name) {
    this.name = name;
  }

  public PassportDetail getPassportDetail() {
    return passportDetail;
}

  public void setPassportDetail(PassportDetail passportDetail) {
    this.passportDetail = passportDetail;
  }

}

How to do it…

In this section, we will take a look at how to insert a record step by step.

Inserting a record

Using the following code, we will insert a Person object with a PassportDetail one:

Code

  PassportDetail detail = new PassportDetail();
  detail.setPassportNo("G51546645");

  Person person = new Person();
  person.setName("Vishal");
  person.setPassportDetail(detail);

  Transaction transaction = session.getTransaction();
  transaction.begin();

  session.save(person);
  transaction.commit();

Output

  Hibernate: insert into passport_detail (passportno) values (?)
  Hibernate: insert into person (name, passport_detail_id) values (?,?)

Here, we created PassportDetail and Person objects and saved both to the database.

How it works...

Here, the one-to-one relationship is not directly known to the database, but it is created for simplicity purposes and is useful to define a user-specific scenario. This means that each Person has one and only one PassportDetail object, and PassportDetail does not exist without Person.

As we used the @OneToOne annotation in the preceding code, hibernate will consider that we want to have a one-to-one relationship between both the tables.

Let's take a look at an option used in the preceding code in detail:

cascade=CascadeType.ALL:

This option in the @OneToOne annotation shows that hibernate uses cascading for all database operations. Here, we save a Person record, but before saving a Person object, it saves a PassportDetail object because PassportDetail is referred to by the Person object. If the PassportDetail object is not persisted at the time of saving the Person object, and the appropriate CascadeType option is not used, it throws an error similar to "Exception in thread "main" org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: "PassportDetail".

The @JoinColumn annotation is used to define the relationship between tables—in our case, between the person table and a column created with the name "passport_detail_id"—and it refers to the primary key of the " "passport_detail " table, which is "id".

In other words, it creates a foreign key reference.

There's more…

Here, we will take a look at the bidirectional way to achieve the relationship.

The logic behind this technique is that each row in the parent table knows its child record identity, and each row from child table knows its parent record identity. For example, in our case, Person knows its PassportDetail record, and PassportDetail knows its Person record; so, we can get the detail for both using any one table.

Here, we will use the same tables/classes structure as the one in the previous section with minor changes.

Creating the tables

Use the following script to create the tables if you are not using hbm2dll=create|update:

Use the following script to create the passport_detail table:

CREATE TABLE `passport_detail` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `passportno` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
);

Use the following script to create the passport_detail table:

CREATE TABLE `person` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) DEFAULT NULL,
  `passport_detail_id` bigint(20) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `FK_PERSON_ID` (`passport_detail_id`),
  CONSTRAINT `FK_PERSON_ID` FOREIGN KEY (`passport_detail_id`) REFERENCES `passport_detail` (`id`)
);

Creating the classes

Use the following code to create the classes:

Source file: Person.java

@Entity
@Table(name = "person")
public class Person {

  @Id
  @GeneratedValue
  @Column(name = "id")
  private long id;

  @Column(name = "name")
  private String name;

  @OneToOne(cascade = CascadeType.ALL)
  @JoinColumn(name = "passport_detail_id")
  private PassportDetail passportDetail;

  public long getId() {
    return id;
  }

  public void setId(long id) {
    this.id = id;
  }

  public String getName() {
    return name;
  }

  public void setName(String name) {
    this.name = name;
  }

  public PassportDetail getPassportDetail() {
    return passportDetail;
  }

  public void setPassportDetail(PassportDetail passportDetail) {
    this.passportDetail = passportDetail;
  }

  @Override
  public String toString() {
    return "Person" 

      +"
 Id: " + this.id
      +"
 Name: " + this.name
      +"
 Passport Detail " 
      + "
	 Id: " + this.passportDetail.getId()
      + "
	 PassportNo: " + this.passportDetail.getPassportNo();
        
  } 

} 

Source file: PersonDetail.java

@Entity
@Table(name = "passport_detail")
public class PassportDetail {

  @Id
  @GeneratedValue
  @Column(name = "id")
  private long id;

  @Column(name = "passportno")
  private String passportNo;

  @OneToOne(mappedBy = "passportDetail", cascade = CascadeType.ALL)
  private Person person;

  public long getId() {
    return id;
  }

  public void setId(long id) {
    this.id = id;
  }

  public String getPassportNo() {
    return passportNo;
  }

  public void setPassportNo(String passportNo) {
    this.passportNo = passportNo;
  }

  public Person getPerson() {
    return person;
  }

  public void setPerson(Person person) {
    this.person = person;
  }

  @Override
  public String toString() {
    return "Passport Detail"
      +"
 Id: " + this.id
      +"
 Name: " + this.getPassportNo()
      +"
 Person " 
      + "
	 Id: " + this.person.getId()
      + "
	 PassportNo: " + this.person.getName();
        
}

Inserting a record

Here, we will insert a Person object with a PassportDetail:

Code

PassportDetail detail = new PassportDetail();
detail.setPassportNo("G54624512");

Person person = new Person();
person.setName("Yogesh");
person.setPassportDetail(detail);

Transaction transaction = session.getTransaction();
transaction.begin();

session.save(person);
transaction.commit();

Output

Hibernate: insert into passport_detail (passportno) values (?)
Hibernate: insert into person (name, passport_detail_id) values (?,?)

Retrieving a record using the parent record

Now, we will try to get a PassportDetail (child) record using a Person (parent) record. Execute the following code:

Code

Criteria criteria = session.createCriteria(Person.class);
Person person = (Person) criteria.uniqueResult();
System.out.println(person.toString());

Output

Hibernate: select this_.id as id1_1_1_, this_.name as name2_1_1_, this_.passport_detail_id as passport3_1_1_, passportde2_.id as id1_0_0_, passportde2_.passportno as passport2_0_0_ from person this_ left outer join passport_detail passportde2_ on this_.passport_detail_id=passportde2_.id
Hibernate: select person0_.id as id1_1_1_, person0_.name as name2_1_1_, person0_.passport_detail_id as passport3_1_1_, passportde1_.id as id1_0_0_, passportde1_.passportno as passport2_0_0_ from person person0_ left outer join passport_detail passportde1_ on person0_.passport_detail_id=passportde1_.id where person0_.passport_detail_id=?

Person
  Id: 1
  Name: Yogesh
  Passport Detail 
    Id: 1
    PassportNo: G54624512

Retrieving a record using the child record

Now, we will do the inverse of the preceding example and try to get a Person (parent) record using a PassportDetail (child) record:

Code

Criteria criteria = session.createCriteria(PassportDetail.class);
PassportDetail passportDetail = (PassportDetail) criteria.uniqueResult();
System.out.println(passportDetail.toString());

Output

Hibernate: select this_.id as id1_0_1_, this_.passportno as passport2_0_1_, person2_.id as id1_1_0_, person2_.name as name2_1_0_, person2_.passport_detail_id as passport3_1_0_ from passport_detail this_ left outer join person person2_ on this_.id=person2_.passport_detail_id

Passport Detail
 Id: 1
 PassportNoName: G54624512
 Person 
   Id: 1
   PassportNoName: Yogesh
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.118.226.240