JPA OrderColumn null values on merge

hibernate, java, jpa, jpa-2.0

Solution

This is a known bug HHH-5732 that will be fixed in 4.3. In general there have been a few problems with this functionality, have a look at these recent bug reports:

- HHH-8580 - NPE while deleting items from collection

- HHH-5378 - @OrderColumn not updated when inserting

- HHH-5390 - Index column on inverse List should throw a warning

Initially there where discussions saying that the scenario of usage that you mention is considered not valid from a conceptual point of view, as it meant that the information about the MenuItem `position` is available only on the parent but not on the child.

Later it was mentioned that a better error message would be shown explaining the problem, instead of silently filling `position` with null.

It was also mentioned that the Hibernate documentation itself gave examples similar to the one you presented, and JPA mentioned nothing against it so it should be a valid use case.

The bug fix on HHH-5732 seems to address this. However if you want to apply the fix on your current version, there is one way that will work.

I had the same problem last week with Hibernate 4.1 and could not upgrade, so I applied the following solution:

Add `position` as a private property field in MenuItem, without necessarily giving it getters and setters. Fill in this property yourself and let Hibernate persist it:

public class MenuItem {

     public MenuItem(... other parameters ..., int position) {

     }

     @Column("position")
     private int position;

     .... no getters or setters ...

}

And in the code that adds submenus:

int counter = 0; // some counter keeping the current position being added
MenuItem newItem = service.persist(.., counter); 
parent.getChildren().add(newItem);

This also makes the information about what is the position of the element available at both sides of the relation.

EDIT: see here the Hibernate documentation for this solution

Problem

I'm using JPA 2.0 with Hibernate 4.2.5. I have a bidirectional mapping to the same entity type. ``` @OneToMany(mappedBy = "parent", cascade = { CascadeType.PERSIST, CascadeType.DETACH }, orphanRemoval = true, fetch = FetchType.EAGER) @Fetch(FetchMode.JOIN) @OrderColumn(name = "position", nullable=false) private List<MenuItem> children = new ArrayList<MenuItem>(); @ManyToOne(optional = false, fetch = FetchType.EAGER) @JoinTable(name = "MenuItem_MenuItem", joinColumns = { @JoinColumn(name = "child_id") }, inverseJoinColumns = { @JoinColumn(name = "parent_id") }) private MenuItem parent; ``` This mapping creates a jointable with parent_id, child_id and position columns. When I want to add a child to the parent I do the following: ``` MenuItem newItem = service.persist(..); parent.getChildren().add(newItem); newItem.setParent(parent); service.merge(newItem); service.merge(parent); ``` which generates the following: ``` Hibernate: select nextval ('hibernate_sequence') Hibernate: insert into MenuItem (menu_id, message, messageId, params, id) values (?, ?, ?, ?, ?) Hibernate: insert into MenuItem_MenuItem (parent_id, child_id) values (?, ?) ``` The problem here is that the second insert doesn't include the position property so it remains null. What am I doing wrong? EDIT I'm using spring declarative transaction management, and all my merge and persist methods are annotated with @Transactional. Could it be a problem?

Original source