我们正在创建一个由 JPA 支持的新 Web 应用程序来替换旧的 Web 应用程序。作为迁移的一部分,我们将旧应用程序的数据库转换为一个新的、更复杂的、JPA 管理的数据库。
因此,我编写了一个“脚本”,将旧数据库转换为一组 JPA 实体,然后保存它们。它是这样工作的:
- 根据领域模型的依赖关系创建转换顺序
- 对于每个实体
- 对遗留数据库执行数据库查询
- 将每个获得的表行的新对象存储在内存中的列表中
- 以与转换相同的顺序迭代生成的列表,并持久化每个实体。
现在,前两个步骤运行良好。坚持,但是我得到一个例外。当一个实体与另一个实体有关系时会发生异常。例如,如果我们的一个实体是 a Book
,而另一个实体将Chapter
定义与 的@ManyToOne(optional=false)
关系Book
。在持久化章节后,它会抛出异常java.lang.IllegalStateException: org.hibernate.TransientPropertyValueException: Not-null property references a transient value - transient instance must be saved before current operation: models.Chapter.book -> models.Book
。
当然,这表明这本书的状态有问题:它似乎要么没有设置,要么还没有被持久化。但是,我可以验证Book
在 的转换中是否正确设置了Chapter
,并且我还可以验证在类型实体Book
被持久化EntityManager
之前,所有类型的实体都Chapter
被持久化了。显然,我的 JPA 提供程序没有按预期运行,并且由于某种原因并没有真正持久化我的Book
对象。
什么解决方案可以让我保存已转换到数据库的整个对象图?我使用 Hibernate 作为我的 JPA 提供程序,我还使用 Spring 3.1 来注入依赖项和EntityManager
s。
编辑 1:一些附加信息:我再次验证 entityManager.persist() 在每个书籍对象上调用 entityManager.persist()之前在章节上调用。但是,book 对象的 id 仍然为 null,这意味着它没有正确持久化。尽管没有使用事务,但数据库也仍然是空的。
编辑2:因为我认为从上面的文字中看不清楚:书和章节的故事只是一个例子。任何引用另一个实体的实体都会发生这种情况。这看起来好像我没有正确使用 JPA/Hibernate,而不是没有正确设置我的实体的值。
编辑 3:核心问题似乎是,尽管正确地坚持 Book,拥有所有正确的注释, book.getId() 仍然为空。基本上,Hibernate 并没有在我的实体上设置 ids 在持久化它们之后,当我以后需要使用这些实体时会导致问题。