Hibernate CollectionOfElements EAGER获取重复元素

时间:2009-07-07 15:49:41

标签: java hibernate annotations

我有一个名为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;
    }
}

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

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

我已经在运行之间清除了数据库,我可以在急切和懒惰之间交换此问题。

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

有谁能告诉我为什么急切的抓取会复制对象?

感谢。

6 个答案:

答案 0 :(得分:63)

我遇到了同样的问题 - 当你为@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>();

答案 1 :(得分:29)

在映射中强制执行急切提取通常不是一个好主意 - 最好在适当的查询中指定热切联接(除非你100%确定在任何情况下你的对象都没有意义/有效没有填充该集合)。

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

答案 2 :(得分:6)

我遇到了这个问题,我用

解决了这个问题

criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);

这清除了由子表连接引起的重复。

答案 3 :(得分:2)

您可以使用SELECT DISTINCT(Hibernate Query Language)子句,如下所示

SELECT DISTINCT synonym FROM SynonymMapping synonym LEFT JOIN FETCH synonym.values

DISTINCT子句删除Hibernate中的重复引用。

虽然组件和值类型集合的生命周期都与拥有实体类绑定,但您应该在select子句中声明它们以便检索它们。 (LEFT JOIN FETCH synonym.values)

ChssPly76的答案是另一种方法,但不会忘记根据Set语义覆盖equals和hashcode方法

的问候,

答案 4 :(得分:0)

使用FetchMode.SELECT e.q.而不是使用N + 1查询的BatchSize@BatchSize(size = 200)

如果您必须获取多于1个关联,则

DISTINCTCriteria.DISTINCT_ROOT_ENTITY无效。对于这种情况,请参阅其他解决方案:https://stackoverflow.com/a/46013654/548473

答案 5 :(得分:0)

我只需添加即可实现

session.createCriteria(ModelClass.class).setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);

此帮助删除重复项。