我有一个名为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在下面创建的连接有关但我无法在网上找到明确的答案。
有谁能告诉我为什么急切的抓取会复制对象?
感谢。
答案 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)
。
DISTINCT
和Criteria.DISTINCT_ROOT_ENTITY
无效。对于这种情况,请参阅其他解决方案:https://stackoverflow.com/a/46013654/548473
答案 5 :(得分:0)
我只需添加即可实现
session.createCriteria(ModelClass.class).setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
此帮助删除重复项。