我有这个实体:
@Entity
public class Node
{
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column
protected Long id;
@Column
private String name;
@ManyToOne
@JoinColumn(name = "NODE_ID")
private Node parent;
@OneToMany(mappedBy = "parent")
private List<Node> children = new ArrayList();
}
假设有一个外部源生成一个树,并且我想导入(读取make persistent)整个树:
public void importTree()
{
Node root = someExternalSource.receiveTree();
// service.preOrderSave(root); ERROR - Not-null property references a transient value
// service.postOrderSave(root); ERROR - Not-null property references a transient value
// no way out :(
}
请注意,绝对希望避免级联,因为这是一种例外情况,它会干扰正常的应用程序逻辑。
我不明白为什么在调用em.persist
/ em.merge
而不是在事务提交时抛出 TransientPropertyValueException 。
但是,有什么办法吗?
由于
这是代码的其余部分:
public Node receiveTree()
{
// dummy code
Node root = new Node();
root.setName("root");
Node child = new Node()
child.setName("child");
root.getChildren().add(child);
child.setParent(root);
return root;
}
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public void preOrderSave(Node node)
{
em.persist(node);
for(Node child : node.getChildren())
{
preOrderSave(child);
}
}
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public void postOrderSave(Node node)
{
for(Node child : node.getChildren())
{
postOrderSave(child);
}
em.persist(node);
}
答案 0 :(得分:0)
似乎这个问题是由@GeneratedValue(strategy = GenerationType.IDENTITY)
引起的,它迫使hibernate立即刷新insert语句(或类似的东西,我没有做足够的代码挖掘)。
切换到另一个策略,解决它:
/** The id. */
@XmlTransient
@Id
// NOK, forces immediate flush
// @GeneratedValue(strategy = GenerationType.IDENTITY)
// NOK, in my case defaults to IDENTITY
// @GeneratedValue(strategy = GenerationType.AUTO, generator = "sequence_generator")
// NOK, MySQL doesn't support sequences...
// @SequenceGenerator(name = "sequence_generator", sequenceName = "GLOBAL_SEQUENCE", allocationSize = 100, initialValue = 1000)
// OK, but ACID is lost
@GeneratedValue(strategy = GenerationType.TABLE, generator = "table_generator")
@TableGenerator(name = "table_generator", table = "SEQUENCE_GENERATOR", pkColumnName = "NAME", valueColumnName = "NEXT_VAL", allocationSize = 100)
@Column(name = "ID")
protected Long id;