java - 当所有@OneToMany都是cascade=ALL时,org.hibernate.TransientObjectException

标签 java hibernate guava

我有一个小型数据结构,我使用 JPA 注释在 Hibernate 中序列化它:

(下面非常简化)

public class Result {
   @Id
   @GeneratedValue(strategy=GenerationType.IDENTITY)
   public int id;


   @OneToMany(cascade=CascadeType.ALL)
   @OrderColumn("row")
   @JoinColumn("ResultId)
   public List<Row> rows
}

public class Row {
   @Id
   @GeneratedValue(strategy=GenerationType.IDENTITY)
   public int id;

   @ElementCollection
   @OrderColumn("col")
   public List<Double> value;
}

当我尝试persist()结果时,我收到 TransientObjectException。怎么可能? cascade=ALL 不应该解决这个问题吗?

最佳答案

事实证明,我在 Hibernate 和 Guava(Google Collections)之间遇到了相当多的交互。事实上,Guava 的这一功能确实需要更明确地公布。

我的问题中的代码示例不完整。相关的(和缺失的)细节是我有一个 Result 的构造函数,它将 List<List<Double>> 作为参数 - 这对于应用程序的其余部分来说更加自然。

不幸的是,Hibernate 不擅长存储二维数组,因此 Row 类是一个快速解决方法。

为了维护与其余代码的接口(interface),我在构造函数中使用 - 还有什么 - 来自 Guava 的 List<List<>>List<Row> 转换为 Lists.transform

当我尝试将生成的对象保存到数据库时,我从 Hibernate 中得到了异常:

org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: <my class here>

我调试得更深入一些,我意识到 Row 对象调用了 setId,而不是调用 getId 的行对象(我有 getter 和 setter - 我的代码示例中的另一个简化)。

然后我就明白了。 transform() 生成基础列表的 View ,而不是副本。每次我请求一个转换后的对象时,它都会从头开始创建,并将全新的“id”字段初始化为 0。

让这成为一个教训:如果您的转换添加了额外状态的可能性,请遵循 Guava Lists.transform 文档中的建议:

To avoid lazy evaluation when the returned list doesn't need to be a view, copy the returned list into a new list of your choosing.

关于java - 当所有@OneToMany都是cascade=ALL时,org.hibernate.TransientObjectException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18409083/

相关文章:

java - JPA:列在其父级中应该是唯一的。

java - Gradle 项目创建中的构建错误

java - 如何将反引号放在名为 key for hibernate 的列名中

java - Google 集合不同谓词

java - Guava Joiner 对 null 元素抛出 NPE

java - 使用 Guava Graph 通过 ID 获取节点

java - 如何在 Java 中显示/隐藏没有任何动画(例如淡入淡出)的软键盘?

java - 在 Java 中,在类的主体中声明和初始化 java.util.(ex.list) 与首先导入相比有什么好处?

hibernate -如何限制多个用户同时读取记录?

Spring boot和hibernate中Mysql 'Like'搜索