Hibernate:合并两个相关的实体

时间:2016-04-29 16:00:33

标签: java hibernate jpa

我有这个实体:

@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);
}

1 个答案:

答案 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;