Hibernate返回了包含空值的列表(使用List类型的OneToMany注释)

7

我遇到了一个问题,Hibernate(4.1.8.FINAL)返回一个包含NULL值的列表(单向OneToMany映射)。

我的问题: 我得到了一个大小为21的List,其中EntryAddress在第10个索引上,第2个EntryAddress在第20个索引上。

Entry [addresses=[null, null, null, null, null, null, null, null, null, null, EntryAddress [id=5, entryId=3, precedence=10, line=Line 3.1], null, null, null, null, null, null, null, null, null, EntryAddress [id=6, entryId=3, precedence=20, line=Line 3.2]]]

我期望的是 - 我期望得到一个只包含两个EntryAddress对象的列表:

Entry [addresses=[EntryAddress [id=5, entryId=3, precedence=10, line=Line 3.1], EntryAddress [id=6, entryId=3, precedence=20, line=Line 3.2]]]

以下是最简源代码:

这里是最简源代码:

@Entity
@Table(name = "entry")
public class Entry {
    ...
    @OneToMany(fetch = FetchType.EAGER, orphanRemoval = true)
    @JoinColumn(name = "entry_id")
    @OrderColumn(name = "precedence")
    private List<EntryAddress> addresses;
    ...
}

@Entity
@Table(name = "entry_address")
public class EntryAddress {
    @Id
    @GeneratedValue
    @Column(name = "id")
    private Integer id;

    @Column(name = "entry_id")
    private Integer entryId;

    @Column(name = "precedence")
    private Integer precedence;
...
}

以下是 mysql 结构(引擎为 InnoDB):
CREATE TABLE  entry  (
   id  int(10) unsigned NOT NULL AUTO_INCREMENT,
   name  varchar(500) NOT NULL,
   active  int(1) NOT NULL DEFAULT '0',
   modifiedTS  timestamp NOT NULL DEFAULT '0000-00-00 00:00:00' ON UPDATE CURRENT_TIMESTAMP,
   createdTS  timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
  PRIMARY KEY ( id )
) ENGINE=InnoDB  DEFAULT CHARSET=utf8;

-- --------------------------------------------------------

CREATE TABLE  entry_address  (
   id  int(10) unsigned NOT NULL AUTO_INCREMENT,
   entry_id  int(10) unsigned NULL,
   precedence  int(2) NULL DEFAULT '0',
   line  varchar(255) DEFAULT NULL,
  PRIMARY KEY ( id ),
  UNIQUE KEY  entry_address_uq  ( entry_id , precedence )
) ENGINE=InnoDB  DEFAULT CHARSET=utf8;

当我试图用“Set”替换“List”时,集合不会有NULL值,但是顺序/先例不起作用。
我发现一个有趣的点是,如果我将第一个EntryAddress的优先级设置为1,并将第二个EntryAddress的优先级设置为2,那么我将得到一个大小为2的列表。因此,尽管优先级只应用于排序,但它似乎在返回列表时也起了作用。
请问我做错了什么?谢谢 :-)
3个回答

17
根据OrderColumn的javadocs文档,订单列必须是整数类型。持久性提供程序在更新关联或元素集合时维护订单列值的连续(非稀疏)排序。第一个元素的订单列值为0。因此,期望的是OrderColumn的值从0开始且为连续值。当值不连续时,Hibernate会向Java列表中添加空元素。我认为OrderColumn的这种行为类似于Hibernate XML映射中的列表索引行为。

2
问题在于List和Set之间的区别。
引用: 我得到了一个大小为21的List,其中EntryAddress位于第10个索引上,第2个Entry Address位于第20个索引上。
这实际上是应该是一个List,却变成了Set!
当你“用Set替换List”时,你记得删除@OrderColumn(name = "precedence")吗?因为如果你使用Set,就不能有一个Order column。

1
谢谢您的回复。是的,我知道如果要使用Set,我必须删除@OrderColumn,但我还想按优先级列对EntityAddress进行排序。这就是为什么我尝试使用List类型的原因。有什么建议吗?我也尝试过使用OrderBy注释,但失败了。 - pitschr

1

我找到了解决方案,使用它后问题得到了解决。

@OneToMany(orphanRemoval = true)
@LazyCollection(LazyCollectionOption.FALSE)
@JoinColumn(name = "entry_id")
@OrderBy("precedence")
private List<EntryAddress> addresses;

@OneToMany(orphanRemoval = true)
@LazyCollection(LazyCollectionOption.FALSE)
@JoinColumn(name = "entry_id")
@OrderBy("precedence")
private List<EntryContact> contacts;

4
请扩展你的答案。是哪一部分解决了你的问题?@LazyCollection? - David Victor
我认为修复方法是将OrderColumn替换为OrderBy。也就是说,Satish的答案是正确的,但缺少了这个关键部分。 我认为@LazyCollection=FALSE具有与设置FetchType.EAGER相同的效果。 - Flávio Etrusco

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