Hibernate 3.5中的@OrderColumn注解

26

我正在尝试在Hibernate 3.5中使用@OrderColumn注释。

@OneToMany(mappedBy = "parent",fetch=FetchType.EAGER, cascade=CascadeType.ALL)
@OrderColumn(name = "pos")
private List<Children> childrenCollection;

在检索数据时,一切都正常。但我无法重新排序列表中的元素并将新的顺序保存到数据库中。


你能展示一下如何重新排序列表并保存回数据库吗? - Arthur Ronald
我尝试创建新的ArrayList并使用parent.setChildrenCollection(newList)进行设置,尝试对检索到的列表进行Collections.sort操作,也尝试从集合中删除null项,但什么都没有发生。父级中的其他更改已保存到数据库,但列表没有任何变化。 - Piotr Gwiazda
Hibernate 3.5不是针对JPA 1.0的吗?@OrderColumn不是JPA 2.0的特性吗? - Neil Stockton
3个回答

34

由于Hibernate不支持@OneToMany(mappedBy="...")和@OrderColumn的组合,因此会出现错误消息。该JIRA问题跟踪了一个请求,以在使用此无效组合时抛出更明显的错误消息:http://opensource.atlassian.com/projects/hibernate/browse/HHH-5390

我认为这主要是因为它是一种奇怪的关系模式而不被支持。上面的注释表明“一”方面决定了如何将关系刷新到数据库中,但是只有通过检查列表才能在“多”方面获得顺序/位置。更合理的做法是让“多”方拥有关系,因为该方面知道元素的成员资格和排序。

Hibernate注释文档对此情况进行了详细描述:

http://docs.jboss.org/hibernate/stable/annotations/reference/en/html_single/#entity-hibspec-collection-extratype-indexbidir

解决方法是移除"mappedBy"属性,这会导致关联使用默认的连接表策略而不是目标表上的列。您可以使用@JoinTable注释指定连接表的名称。
此更改的净效果是,关系的“多”侧现在确定如何持久化关系。因为Hibernate在刷新实体时现在会忽略“一”侧,所以您的Java代码需要确保List被正确更新。
如果您仍然希望在Java中访问“一”侧,请将其映射为:
@ManyToOne
@JoinColumn(name="...", insertable=false, updatable=false, nullable=false)

6
有趣的是,“明确索引列”的“官方”示例恰好使用 @OneToMany(mappedBy="...")@OrderColumn 的组合(参见 http://docs.jboss.org/hibernate/core/3.6/reference/en-US/html/collections.html#collections-indexed 中的示例7.8)。 - Chris Lercher
3
在这个回答之后,大家都同意必须支持这种情况。Gail Badner表示:“我同意 @OneToMany (mappedBy="...") 应该得到支持。” - Arjan Tijms
1
是否有其他支持@OneToMany (mappedBy="...")的JPA提供者(例如Eclipselink)? - deamon
7
我天真地猜想每个供应商都支持这个,因为它是一种相当标准的映射关系。像往常一样,Hibernate是与众不同的那一个。它基本上是JPA供应商中的IE6 :( - Mike Braun
2
我不知道为什么这被称为“奇怪的关系模式”。它并不是。只需要问问JPA的人就行了。 - Kawu
显示剩余2条评论

10

可以这样做:

@Entity
class Parent {

    @OneToMany
    @OrderColumn(name = "pos")
    List<Child> children;
}

@Entity
class Child {

    @ManyToOne
    Parent parent;
    @Column(name = "pos")
    Integer index;

    @PrePersist
    @PreUpdate
    private void prepareIndex() {
        if (parent != null) {
            index = parent.children.indexOf(this);
        }
    }
}

2
我认为在prepareIndex()函数中应该更改为: index = parent.children.indexOf(this); 如果(index == -1),则 index = parent.children.size(); - cn123h

4
您应该尝试在关联的所有者上指定OrderColumn。 或者在您的映射中,您将所有者放在了子类上,而所有者应该是父类(在双向关联中,所有者是没有mappBy关键字的那个,这里您将此关键字放在了父类上,那么就意味着父类不是所有者)。
在您的子类中,应该在parentCollection上使用mappedBy关键字。但是childrenCollection上不需要。
在您的父类中,应该有@JoinTable注释,就像这样:
@OneToMany(mappedBy = "parent",fetch=FetchType.EAGER, cascade=CascadeType.ALL)
@OrderColumn(name = "pos")
@JoinTable( name = "<NAME_OF_YOUR_TABLE>", joinColumns = @JoinColumn( <JOIN_COLUMNS_...> )
private List<Children> childrenCollection;

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接