2

我有一个小型数据结构数据结构,我使用 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 不应该解决这个问题吗?

4

1 回答 1

2

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

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

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

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

当我尝试将生成的对象保存到 DB 时,我从 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()生成基础列表的视图,而不是副本。每次我要求转换的对象时,它都是从头开始创建的,全新的“id”字段初始化为 0。

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

当返回的列表不需要是视图时,为避免延迟评估,请将返回的列表复制到您选择的新列表中。

于 2013-08-23T18:10:23.387 回答