我有一个小的数据结构数据结构,我使用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来处理这个吗?
答案 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
文档中的建议:
当返回的列表不需要时,避免延迟评估 查看,将返回的列表复制到您选择的新列表中。