2016-04-29 5 views
0

J'ai cette entité:Hibernate: fusionner deux entités liées

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

Supposons qu'il y ait une source externe qui génère un arbre, et que je veux importer (lire faire persistant) cet arbre tout:

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 :(
} 

Notez que je absolument veux éviter cascade parce que c'est un cas exceptionnel, et il interférerait avec Applicat normale la logique des ions.

Ce que je ne comprends pas pourquoi TransientPropertyValueException est jeté lors de l'appel em.persist/em.merge au lieu de validation de la transaction.

Cependant, y a-t-il un moyen de s'en sortir?

Merci


c'est le reste du 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); 
} 

Répondre

0

Il semble que ce problème est causé par @GeneratedValue(strategy = GenerationType.IDENTITY), qui force mise en veille prolongée à rincer immédiatement la déclaration d'insertion (ou quelque chose comme ça, je n'ai pas assez creusé le code).

Le passage à une autre stratégie, il permet de résoudre:

/** 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;