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?