【问题标题】:Cannot persist Entity with Shared ID无法持久化具有共享 ID 的实体
【发布时间】:2019-02-01 00:40:31
【问题描述】:

我正在练习 JavaEE 技术。现在我专注于使用 Hibernate 的 JPA。该项目有以下实体:

书籍:

@Entity @Table(name = "book")
public class Book extends BaseEntity<Long> {
   @Id
   private Long id;

   @NotNull
   private String name;

   @OneToOne(mappedBy = "book", cascade = CascadeType.ALL)
   private BookDetails details;

   //getters/setters
}

书籍详情:

@Entity
@Table(name = "book_details")
public class BookDetails extends BaseEntity<Long> {

    @Id
    private Long id;

    @MapsId
    @OneToOne
    private Book book;

    @NotNull
    @Column(name = "number_of_pages")
    private int numberOfPages;

    //getters/setters
}

现在,各个 EJB 服务类:

图书服务:

@Stateless
public class BookService extends BaseEntityService<Long, Book> {

    public void createBook(Book book) {
        super.getEntityManager().persist(book);
    }

    //update, delete, find and findAll methods
}

BookDetailsS​​ervice:

@Stateless
public class BookDetailsService extends BaseEntityService<Long, BookDetails> {

    public void createBookDetails(BookDetails details) {
        super.getEntityManager().persist(details);
        //super.persist(details); //This method would not work to persisting entity with shared Id, because it verifies if ID is null
    }
    //update, delete and find methods
}

问题:

当我尝试保留一本新书及其详细信息时:

Book b = new Book();
b.setId(123L);
b.setName("Bible");

bookService.createBook(b);
//The entity Book  is correctly persisted in the DB.
BookDetails d = new BookDetails();
d.setNumberOfPages(999);
d.setBook(b);

//b.setDetails(d); //don't do this

bookDetailsService.createBookDetails(d);
//BookDetails is not persisted in the DB, throws exception....

抛出以下异常:

java.sql.SQLIntegrityConstraintViolationException: Duplicate entry '123' for key 'PRIMARY'

Book 实体是持久化的,但不是BookDetails


我遵循了这个教程:

其他信息:

  • JDK 1.8
  • 帕亚拉 5
  • MySQL 8.0
  • 休眠 5.3.4
  • OmniPersistence 图书馆。 (适用于 JPA、JDBC 和数据源的实用程序

您可以查看项目存储库here

【问题讨论】:

  • 你可以在这里看到它:docs.jboss.org/hibernate/orm/5.3/userguide/html_single/… 无论如何,我会尝试使用@PrimaryKeyJoinColumn 注释。
  • @NathanHughes 虽然我用@PrimaryKeyJoinColumn 替换了@MapsId,但它仍然不起作用。但是,异常更改为:java.sql.SQLException: Field 'book_id' doesn't have a default value。所以我尝试设置BookDetailsd.setId(b.getId()))的id,但仍然显示相同的错误。

标签: java hibernate jpa jakarta-ee


【解决方案1】:

我已经可以解决这个问题,这是由于实体的持久化方式和 JavaEE 应用程序中方法的事务性。

当调用持久化类的 EJB 的业务方法时,在此方法完成后事务结束,因此持久性上下文关闭,附加类(托管)变为分离(非托管)。见this

所以在坚持Bookb之后:

bookService.createBook (b);

该事务结束,这就是这本书被持久化的原因,此外,它不再被管理。因此,当我将这本书链接到详细信息时:

d.setBook (b);

这是为了持久化共享 Id 的实体而必须做的事情,必须管理父实体(在本例中为 b)。


我可以找到两种解决方案:

解决方案 1:

将书 b 附加到详细信息创建事务的持久性上下文中。见this

b = getEntityManager.merge(b);

Solución 2:(我选择的那个)

BookDetailsService的业务方法中调用BookService业务方法,这意味着转移依赖注入。因此,通过持久化两个实体来进行单个事务。

//BookDetailsService class
@Inject
BookService bookService;

public void createBookDetails(BookDetails details) {
    Book b = new Book();
    b.setId(details.getId());
    b.setName("Bible");

    bookService.createBook(b);

    details.setBook(b);//b still managed

    super.persist(details);
}

我认为这个解决方案更加简洁和连贯,因为BookDetailsService 将始终需要来自BookService 的服务。

【讨论】:

    【解决方案2】:

    Book 类的 BookDetails 属性上的@OneToOne 表示从 Book 到 BookDetails 存在一对一的关联。另外,请注意 cascade = CascadeType.ALL 的使用。由于没有 Book 实体就无法存在 BookDetails 实体,使用此级联设置,BookDetails 实体将在后续更新/删除 Book 实体时更新/删除。

    【讨论】:

      【解决方案3】:

      您必须在书籍详细信息上添加 cascadetype:

      @OneToOne(mappedBy = "book", cascade = CascadeType.ALL)
      private BookDetails details;
      

      更多详情请参考here CascadeType.ALL 将在保存书籍实体时执行所有操作,例如保存、删除和合并。 现在,由于我们在 Book 实体中添加了 CascadeType.ALL,您必须在 book 中设置 bookdetails 对象。见下文:

      Book b = new Book();
      BookDetails d = new BookDetails();
      b.setBookDetails(d);
      b.setId(123L);
      b.setName("Bible");
      
      d.setId(111L); //random id that is not existing if d is new record
      d.setNumberOfPages(999);
      bookService.createBook(b);
      

      保存书籍实体将保存书籍以及书籍详细信息实体。您也可以尝试hibernate.show_sql=true 来查看保存图书实体时执行的所有查询。

      【讨论】:

      • 我已经更新了我的答案。如果这仍然不起作用,请分享您如何保存图书实体。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-02-21
      • 2016-01-23
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多