Skip to content
Advertisement

What am I doing wrong in this one to one bi-directional mapping?

I have two classes: Person and PersonDetail

Person:

package com.sam.entity;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToOne;
import javax.persistence.Table;

import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import lombok.Setter;
import lombok.ToString;

@Entity
@Table(name = "person")
@ToString
@NoArgsConstructor
@RequiredArgsConstructor
public class Person {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    @Getter
    @Setter
    private int id;

    @Column(name = "first_name")
    @Getter
    @Setter
    @NonNull
    private String firstName;

    @Column(name = "last_name")
    @Getter
    @Setter
    @NonNull
    private String lastName;

    @Column(name = "email")
    @Getter
    @Setter
    @NonNull
    private String email;

    // Defining the relationship between instructor and instructor detail
    @OneToOne(cascade = CascadeType.ALL)
    @JoinColumn(name = "person_detail_id")
    @Getter
    @Setter
    @ToString.Exclude
    private PersonDetail personDetail;
}

PersonDetail

package com.sam.entity;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToOne;
import javax.persistence.Table;

import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import lombok.Setter;
import lombok.ToString;

@Entity
@Table(name = "person_detail")
@ToString
@NoArgsConstructor
@RequiredArgsConstructor
public class PersonDetail {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    @Getter
    @Setter
    private int id;

    @Column(name = "youtube_channel")
    @Getter
    @Setter
    @NonNull
    private String youtubeChannel;

    @Column(name = "hobby")
    @Getter
    @Setter
    @NonNull
    private String hobby;

    // adding a reference to the person for bi-directional mapping
    @OneToOne(mappedBy = "personDetail", cascade = CascadeType.ALL)
    // this references the personDetail in the person class
    @Getter
    @Setter
    private Person person;
}

I have set up a bi-directional one-to-one mapping between these classes. I am trying to save a person and that person’s details and then I am trying to fetch the person using the person’s details. The code for that is:

package com.sam.tests;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import com.sam.demo.HibernateUtil;
import com.sam.entity.Person;
import com.sam.entity.PersonDetail;

public class HibernateOneToOneBidirectional {
    private static SessionFactory sessionFactory;
    private Session session;

    @BeforeAll
    public static void setup() {
        sessionFactory = HibernateUtil.getSessionFactory("hibernate.onetoone.bidirectional.xml");
    }

    @AfterAll
    public static void teardown() {
        sessionFactory.close();
    }

    @BeforeEach
    public void openSession() {
        session = sessionFactory.getCurrentSession();
    }

    @AfterEach
    public void closeSession() {
        session.close();
    }

    @Test
    @DisplayName("Get person from person detail(Testing out bi-directional mapping)")
    public void testBiDirectional() {
        session.beginTransaction();
        Person person = new Person("John", "Smith", "johnsmith@movie.com");
        PersonDetail personDetails = new PersonDetail("youtube.com/johnsmith", "Acting");
        person.setPersonDetail(personDetails);
        session.save(person);

        // fetch the stored personDetail
        System.out.println("Person detail id is: " + personDetails.getId());
        PersonDetail savedDetail = session.get(PersonDetail.class, personDetails.getId());
        System.out.println("Fetched person details are: " + savedDetail);
        // using the fetched personDetail, fetch the person
        Person associatedPerson = savedDetail.getPerson();
        session.getTransaction().commit();
        Assertions.assertTrue(associatedPerson != null);
    }

}

My test is failing because the person detail object has a null value for the associated person. Can someone help me?

Advertisement

Answer

I tried fetching the person details in another session and that worked. I could see the details of the person. The edited code is:

package com.sam.tests;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import com.sam.demo.HibernateUtil;
import com.sam.entity.Person;
import com.sam.entity.PersonDetail;

public class HibernateOneToOneBidirectional {
    private static SessionFactory sessionFactory;
    private Session session;

    @BeforeAll
    public static void setup() {
        sessionFactory = HibernateUtil.getSessionFactory("hibernate.onetoone.bidirectional.xml");
    }

    @AfterAll
    public static void teardown() {
        sessionFactory.close();
    }

    @BeforeEach
    public void openSession() {
        session = sessionFactory.getCurrentSession();
    }

    @AfterEach
    public void closeSession() {
        session.close();
    }

    @Test
    @DisplayName("Get person from person detail(Testing out bi-directional mapping)")
    public void testBiDirectional() {
        session.beginTransaction();
        Person person = new Person("John", "Smith", "johnsmith@movie.com");
        PersonDetail personDetails = new PersonDetail("youtube.com/johnsmith", "Acting");
        person.setPersonDetail(personDetails);
        session.save(person);
        int id = personDetails.getId();
        session.close();

        Session anotherSession = sessionFactory.getCurrentSession();
        anotherSession.beginTransaction();
        // fetch the stored personDetail
        PersonDetail savedDetail = anotherSession.get(PersonDetail.class, id);
        System.out.println("Fetched person details are: " + savedDetail);
        // using the fetched personDetail, fetch the person
        Person associatedPerson = savedDetail.getPerson();
        anotherSession.getTransaction().commit();
        anotherSession.close();
        Assertions.assertTrue(associatedPerson != null);
    }

}

Is this correct? Or can this be done in the same transaction?

User contributions licensed under: CC BY-SA
8 People found this is helpful
Advertisement