休眠 - @OneToOne 关系

时间:2021-02-06 09:46:17

标签: java hibernate one-to-one

我正在尝试建立一对一的关系。在所有者方面,bookIsn(非主键)是指目标实体的主键。 现在的问题是,如果我想阅读所有评论 (reviewRepository.findAll()),如果给定的 bookIsn 没有可用的书籍,则会引发以下错误:

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

但预期行为是,如果找不到书,则书实体仅设置为 null。就像我使用 reviewId 加入列 @JoinColumn( name = "review_id", ... ) 而不是 review_isn 一样。

有人可以解释为什么它使用主键而不是非主属性吗?需要做什么才能使其也适用于非主要属性?

下面两个类:

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;

}

1 个答案:

答案 0 :(得分:1)

首先我要说的是,我不建议您在 hibernate 实体类中使用 @Data lombok 注释。参见示例 this 文章。

然后,我建议您以这种方式更正您的 Review 实体映射:

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;
   }
}

您可以通过以下方式保留您的 Review 实体:

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

附言另请注意,由于潜在的性能问题,it is not recommended 使用字符串作为大表的主键类型。