Hibernate PostgreSQL OneToOne Relationship Trigger Child Query First

Viewed 289

I'm building app to learn Hibernate on PostgreSQL. And I'm currently trying to add variable to database that has OneToOne relationship.

First, I create two tables in my database with schema below. On person_detail table it has primary key that's also foreign key to person table.

Database Schema

Then I created two classes, Person and PersonDetail. PersonDetail is child of Person that has OneToOne relationship. And I use code below to add person with personDetail as attribute.

Person person = new Person(
        "Rick",
        1.7,
        dateFromString("1969-4-2"),
        new Date()
);
PersonDetail personDetail =
        new PersonDetail("myemail@email.com", "Marley");
person.setPersonDetail(personDetail);

session.beginTransaction();

session.save(person);
session.save(personDetail);

session.getTransaction().commit();

System.out.println(person.toString());

But the problem with code above is that Hibernate execute child query first instead of parent query.

Hibernate: insert into person_detail (address, email) values (?, ?)

And since person still empty, we cannot insert any row to person_detail because it violates foreign key constraint.

Is there a way to solve this? Thanks!

In case some one want to check how I annotate those two classes, I put the code below.

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

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

    @Column(name="height")
    private double height;

    @Column(name="birth_date")
    private Date dateBirth;

    @Column(name="last_seen")
    private Date lastSeen;

    @OneToOne(cascade = CascadeType.ALL)
    @JoinColumn(name = "id")
    private PersonDetail personDetail;

    public Person() {}

    public Person(String name, double height, Date dateBirth, Date lastSeen){
        this.name = name;
        this.height = height;
        this.dateBirth = dateBirth;
        this.lastSeen = lastSeen;
    }
}


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

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

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

    public PersonDetail(){}

    public PersonDetail(String email, String address){
        this.email = email;
        this.address = address;
    }
}
1 Answers

I see that you have primary key in table person_details as foreign key to person table, you can use @PrimaryKeyJoinColumn like this:

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

    @Id
    @Column(name = "id")
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

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

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

    @OneToOne(mappedBy = "person", cascade = CascadeType.ALL)
    @PrimaryKeyJoinColumn
    private PersonDetail personDetail;

    public Person() {}

    public Person(String name, String height) {
        this.name = name;
        this.height = height;
    }
}

@Data
@Entity
@Table(name="person_detail")
public class PersonDetail {

    @Id
    @Column(name="id")
    private Long id;

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

    @OneToOne
    @MapsId
    @JoinColumn(name = "id", referencedColumnName = "id")
    private Person person;


    public PersonDetail(){}

    public PersonDetail(String email){
        this.email = email;
    }
}

And if you save your entity, don't forget set Person to PersonDetails:

Person person = new Person("Rick", "1.7");
        
PersonDetail personDetail = new PersonDetail("myemail@email.com");
personDetail.setPerson(person);

person.setPersonDetail(personDetail);
        
repository.save(person);
Related