I have this entity:
@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();
}
Suppose there is an external source that generates a tree, and that I want to import (read make persistent) this whole tree:
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 :(
}
Note that I absolutely want to avoid cascade because this is an exceptional case, and it would interfere with the normal application logic.
What I don't understand is why TransientPropertyValueException is thrown when calling em.persist
/ em.merge
instead on transaction commit.
However, is there any way out?
Thanks
this is the rest of the code:
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);
}
It seems this problem is caused by @GeneratedValue(strategy = GenerationType.IDENTITY)
, which forces hibernate to flush immediately the insert statement (or something like this, I haven't done enough code-digging).
Switching to another strategy, solves it:
/** 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;
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.