Joko
Joko

Reputation: 65

Hibernate - @OneToOne relation

I'm trying to create a one-to-one relationship. On the owner side, the bookIsn (non-primary) is referring to the primary key of the target entity. Now the issue is if I want to read all reviews (reviewRepository.findAll()) the following error is thrown if no book is available for the given bookIsn:

Unable to find com.repository.model.Book with id 1

But the expecting behavior would be that the book entity simply is set to null if no book could be found. Like it does if I use the reviewId for joining the column @JoinColumn( name = "review_id", ... ) instead of the review_isn.

Can somebody explain why it's working with a primary key, but not for a non-primary attribute? What needs to be done to make it work for non-primary attributes as well?

Below the two classes:

Review.java:

@Entity
@Data
@Table(name = "review")
public class Review {

  @Id
  @Column(name="review_id")
  private String reviewId;

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

  @OneToOne
  @JoinColumn(
    name = "book_isn",
    referencedColumn = "book_isn",
    insertable = false,
    updatable = false)
  private Book book;
}

Book.java:

@Entity
@Data
@Table(name = "book")
public class Book {

  @Id
  @Column(name="book_isn")
  private String bookId;

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

}

Upvotes: 1

Views: 633

Answers (1)

SternK
SternK

Reputation: 13041

First of all I have to say that I would not suggest you to use @Data lombok annotation with hibernate entity class. See for example this article.

Then, I would suggest you to correct your Review entity mapping in this way:

import javax.persistence.Transient;

@Entity
@Table(name = "review")
public class Review
{
   private String reviewId;
   private Book book;
   
   @Id
   @Column(name = "review_id")
   public String getReviewId()
   {
      return reviewId;
   }
   
   @OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
   @JoinColumn(name = "book_isn")
   public Book getBook()
   {
      return book;
   }
   
   // setters omitted for brevity

   @Transient
   public String getBookId()
   {
      return book != null ? book.getBookId() : null;
   }
}

You can persist your Review entities in the following way:

Book b1 = new Book();
b1.setBookId("BK1");
b1.setBookName("Book 1");
      
Review r1 = new Review();
r1.setReviewId("R1");
r1.setBook(b1);
      
session.persist(r1);

Review r2 = new Review();
r2.setReviewId("R2");
session.persist(r2); // book_isn is NULL for the R2 Review

P.S. Please also note that it is not recommended to use string as a type for primary key for big tables due to the potential performance problem.

Upvotes: 1

Related Questions