Hibernate CollectionOfElements EAGER获取重复元素

Rac*_*hel 41 java annotations hibernate

我有一个名为SynonymMapping的类,它有一组映射为CollectionOfElements的值

@Entity(name = "synonymmapping")
public class SynonymMapping {

    @Id private String keyId;

    //@CollectionOfElements(fetch = FetchType.EAGER)
    @CollectionOfElements
    @JoinTable(name="synonymmappingvalues", joinColumns={@JoinColumn(name="keyId")})
    @Column(name="value", nullable=false)
    @Sort(type=SortType.NATURAL)
    private SortedSet<String> values;

    public SynonymMapping() {
        values = new TreeSet<String>();
    }

    public SynonymMapping(String key, SortedSet<String> values) {
        this();
        this.keyId = key;
        this.values = values;
    }

    public String getKeyId() {
        return keyId;
    }

    public Set<String> getValues() {
        return values;
    }
}
Run Code Online (Sandbox Code Playgroud)

我有一个测试,我将两个SynonymMapping对象存储到数据库,然后要求数据库返回所有保存的SynonymMapping对象,期望接收我存储的两个对象.

当我将值的映射更改为急切(如注释行中的代码所示)并再次运行测试时,我会收到四个匹配项.

我已经清除了运行之间的数据库,我可以复制这个问题在eager和lazy之间交换.

我认为它与hibernate在下面创建的连接有关但我无法在网上找到明确的答案.

任何人都可以告诉我为什么急切的提取是复制对象?

谢谢.

小智 69

我遇到了同样的问题 - 当你为@CollectionOfElements设置FetchType.EAGER时,Hibernate尝试一次性获取所有内容,即对链接到"master"对象的元素的每个条目使用一个单独的查询.如果将@Fetch(FetchMode.SELECT)注释添加到集合中,则可以以N + 1查询为代价成功解决此问题.在我的情况下,我希望有一个MediaObject实体,其中包含其元数据项(视频编解码器,音频编解码器,大小等)的集合.metadataItems集合的映射如下所示:


@CollectionOfElements (targetElement = String.class, fetch = FetchType.EAGER)
@JoinTable(name = "mo_metadata_item", joinColumns = @JoinColumn(name = "media_object_id"))
@MapKey(columns = @Column(name = "name"))
@Column (name = "value")
@Fetch (FetchMode.SELECT)
private Map<String, String> metadataItems = new HashMap<String, String>();

  • 非常感谢你做的这些. (2认同)
  • 花了很长时间来调试这个问题,甚至花了更长的时间来找到不是关于实现集合的教程的答案。感谢分享。 (2认同)

Chs*_*y76 29

在映射中强制执行急切提取通常不是一个好主意 - 最好在适当的查询中指定热切联接(除非您100%确定在任何情况下,如果没有该集合,您的对象将无法理解/有效正在填充).

你得到重复的原因是因为Hibernate内部加入你的根和集合表.请注意,它们确实是重复的,例如,对于具有3个集合元素的2个SynonymMappings,每个将获得6个结果(2x3),每个SynonymMapping实体3个副本.因此,最简单的解决方法是将结果包装在Set中,从而确保它们是唯一的.

  • 但是为什么Hibernate不能过滤掉这些,我不明白为什么你会这样想这样. (38认同)

Raj*_*gan 7

我遇到了这个问题,我用它来解决它

criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);

这样可以清除由子表连接引起的重复项.