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

时间:2013-08-23 18:03:25

标签: 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来处理这个吗?

1 个答案:

答案 0 :(得分: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调用的行对象(我有吸气剂和制定者 - 我的代码示例中的另一个简化。)

然后我突然意识到了。 transform()生成基础列表的视图,而不是副本。每当我要求改造对象时,它都是从头开始创建的,全新的&#34; id&#34;字段初始化为0。

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

  

当返回的列表不需要时,避免延迟评估   查看,将返回的列表复制到您选择的新列表中。