假设,实体A和B之间存在@OneToMany关系。每个A可以有多个B。
@Entity
public class A{
@Id
private long id;
...
@OneToMany(mappedBy="ref")
private List<B> items;
...
}
@Entity
public class B{
@Id
private long id;
@ManyToOne
@JoinColumn(name = "A_ID")
private A ref;
}
此应用程序已投入生产一段时间,保存到数据库中的B的顺序到目前为止并不相关。
然而,现在需要B的确切顺序。为此,我添加了如下的@OrderColumn。
@OneToMany
@OrderColumn(name="B_ORDER")
private List<B> items;
它工作正常,B表现在具有带顺序值的B_ORDER列。
现在需要更新生产数据库。新列B_ORDER已添加到表B中。但是,对于现有行,此列没有值(空)。当您尝试检索已存在记录的B列表时,我得到以下异常:
org.hibernate.HibernateException: null index column for collection
对于旧记录,可以有一个以任何顺序排列的B列表。@OrderColumn具有属性“nullable”,默认情况下为true。但这没有帮助。
是否有JPA方法来实现这一点,或者我必须自己在db中填充这些空值?
将JPA 2.1与Hibernate 4.3.7结合使用。
3条答案
按热度按时间2guxujil1#
您遇到的问题是,JPA提供程序(在您的Hibernate中)需要 * order列的值的连续(非稀疏)排序 *。
但是,当您将新列添加到新数据库中时,这些值将为null,除非您定义了默认值0。
您可能认为添加一个默认值就可以了。抱歉,事实并非如此。如果这样做,您的集合将始终显示最多一个项目。
要解决这个问题,必须为每个集合添加一个连续的非稀疏编号。
实际上,您应该更改实体临时值,以便可以实际访问相应的字段:
现在你可以加载所有项了,接下来你需要写一个临时方法,从数据库加载所有项,并对每个集合中的每个项进行编号,从0开始,直到集合的长度减1。
上面的建议只是我觉得方便的一种方法。有很多方法可以解决它。如果你有足够的时间,你甚至可以手动完成。
从这个答案中你应该了解的是集合中的项需要从0开始编号。否则Hibernate不会将这些项加载到你的集合中。你需要满足here描述的约束。
b5lpy0ml2#
我也遇到过类似的问题:当我更新一个已有父项的子项列表时,hib似乎没有在order列中生成值。我通过在子项上显式添加order列来修复它,如下所示(使用您的示例):
如果我做不到这一点,创建
A
记录(带有B
子项)会正常工作,但是通过添加B
子项来更新A
记录会失败(带有null index column for collection: ...
),因为hib不会为B_ORDER
列生成值。afdcj2ne3#
我采取的步骤
我用的是postgres。