One To One shared primary key mapping issue in Spring JPA

1.5k views Asked by At

I am new to Spring JPA and struggling to save the object

'Tables'

  1. Parent table

bookheader

uid int (PK), booknum varchar

  1. Child table

bookinfo

bookid(FK)(PK), remark varchar

BookHeader.java ...

@Entity
@Table(name="tbookheader", schema="v2")
public class BookHeader implements Serializable{

  @Id
  @SequenceGenerator(name="seq-gen",sequenceName="v2.tbookheader_uid_seq",  allocationSize = 1)
  @GeneratedValue(strategy= GenerationType.IDENTITY, generator="seq-gen")
  @Column(name = "uid")
  private int uid;

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

  @OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "bookHeader")
  private BookInfo bookInfo;
}

BookInfo.java

@Entity
@Table(name="tbookinfo", schema="v2")
public class BookInfo implements Serializable{

  @Id
  @Column(name = "bookid")
  private int uid;

  @OneToOne
  @JoinColumn(name="bookid",referencedColumnName="uid")
  private BookHeader bookHeader;

  private String remark;
}

I am getting object from json and i converted josn to object using GSON.

now i am trying to save it through SPRING JPA

{

    BookHeader.setBookNum("tesetbooking3");

    BookHeader.setUserDate(new Date());

    BookHeader.setUserid(1111);

    BookHeader.setCrtDate(new Date());

    BookHeader.setCrtUserId(1111);

    return bookHeaderRepository.save(BookHeader);
}

But i am getting exception:

ERROR: insert or update on table "tbookinfo" violates foreign key constraint 
"fk_tbookinfo_bookid"
  Detail: Key (bookid)=(0) is not present in table "tbookheader".

Seems generated primary key not passed from the parent table.

Could somebody help me.

TIA.

2

There are 2 answers

1
Selindek On

Change the id properties from int to Integer.

The default value for an int property is 0, which is a valid foreign key, but there is no object in the DB with that key.

0
Alan Hay On

Firstly, you have created a @OneToOne but you have done nothing to indicate that this is a shared primary key model.

BookHeader:

@Entity
@Table(name="tbookheader", schema="v2")
public class BookHeader implements Serializable{

  @Id
  @SequenceGenerator(name="seq-gen",sequenceName="v2.tbookheader_uid_seq",  
                           allocationSize = 1)
  @GeneratedValue(strategy= GenerationType.IDENTITY, generator="seq-gen")
  @Column(name = "uid")
  private Long uid;

  @OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "bookHeader")
  private BookInfo bookInfo;
}

BookInfo:

@Entity
@Table(name="tbookinfo", schema="v2")
public class BookInfo implements Serializable{

  @Id //dependent on BookHeader for Id
  @OneToOne
  @JoinColumn(name="bookid",referencedColumnName="uid")
  private BookHeader bookHeader;
}

Secondly, with a bi-directional relationship - as you have here - you must ensure both sides of the relationship are set correctly on the in-memory model before persisting.

BookHeader header - new BookHeader();
BookInfo info = new BookInfo();
header.setBookInfo(info);
info.setBookHeader(header);//will fail without this
bookHeaderRepository.save(header);