【发布时间】:2013-01-19 16:23:32
【问题描述】:
我们正在创建一个由 JPA 支持的新 Web 应用程序来替换旧的 Web 应用程序。作为迁移的一部分,我们正在将旧应用程序的数据库转换为新的、更复杂的 JPA 管理的数据库。
所以我编写了一个“脚本”,将旧数据库转换为一组 JPA 实体,然后保存它们。它的工作原理是这样的:
- 根据领域模型的依赖关系创建转换顺序
- 对于每个实体
- 对旧版数据库执行数据库查询
- 将获得的每个表行的新对象存储在内存中的列表中
- 以与转换相同的顺序迭代生成的列表,并保留每个实体。
现在,前两个步骤运行良好。坚持,但是我得到一个例外。当一个实体与另一个实体有关系时会发生异常。例如,如果我们的一个实体是Book,另一个是Chapter,定义了与Book 的@ManyToOne(optional=false) 关系。在持久化章节时,它会抛出异常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 来注入依赖项和EntityManagers。
编辑 1:一些附加信息:我再次验证了 entityManager.persist() 在每个书籍对象上被调用之前 entityManager.persist() 在章节上被调用。但是,book 对象的 id 仍然为 null,这意味着它没有正确持久化。尽管没有使用事务,但数据库仍然是空的。
编辑 2:因为我认为从上面的文字中看不清楚:书和章节的故事只是一个例子。它发生在引用另一个实体的 any 实体上。这看起来好像我没有正确使用 JPA/Hibernate,而不是没有正确设置我的实体的值。
编辑 3:核心问题似乎是 尽管 正确地坚持 Book,拥有所有正确的注释,book.getId() 仍然为空。基本上,Hibernate 不会在持久化实体后为其设置 id,这会导致我以后需要使用这些实体时出现问题。
【问题讨论】:
-
如何保存实体?该流程涉及多少实体经理?
-
我通过使用 Spring 的
@PersistenceContext获得的 EntityManager 调用entityManager.persist(entity)来保存我的实体。这是一个相当复杂的领域模型,包含 60 多种不同类型的实体,它们之间存在各种关系。
标签: java hibernate jpa spring-orm