Java Hibernate CollectionOfElements EAGER 获取重复元素
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1093153/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Hibernate CollectionOfElements EAGER fetch duplicates elements
提问by Rachel
I have a class called SynonymMapping which has a collection of values mapped as a CollectionOfElements
我有一个名为 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;
}
}
I have a test where I store two SynonymMapping objects to the database and then ask the database to return all saved SynonymMapping objects, expecting to receive the two objects I stored.
我有一个测试,我将两个 SynonymMapping 对象存储到数据库,然后要求数据库返回所有保存的 SynonymMapping 对象,期望接收我存储的两个对象。
When I change the mapping of values to be eager (as shown in in the code by the commented out line) and run the test again, I receive four matches.
当我将值的映射更改为急切(如代码中注释掉的行所示)并再次运行测试时,我收到四个匹配项。
I have cleared out the database between runs and I can duplicate this problem swapping between eager and lazy.
我已经在运行之间清除了数据库,我可以在急切和懒惰之间交换这个问题。
I think it has to do with the joins that hibernate creates underneath but I can't find a definite answer online.
我认为这与 hibernate 在下面创建的连接有关,但我在网上找不到明确的答案。
Can anyone tell me why an eager fetch is duplicating the objects?
谁能告诉我为什么急切提取会复制对象?
Thanks.
谢谢。
采纳答案by ChssPly76
It's generally not a good idea to enforce eager fetching in the mapping - it's better to specify eager joins in appropriate queries (unless you're 100% sure that under any and all circumstances your object won't make sense / be valid without that collection being populated).
在映射中强制执行预先获取通常不是一个好主意 - 最好在适当的查询中指定预先连接(除非您 100% 确定在任何和所有情况下您的对象在没有该集合的情况下都没有意义/有效被填充)。
The reason you're getting duplicates is because Hibernate internally joins your root and collection tables. Note that they really are duplicates, e.g. for 2 SynonymMappings with 3 collection elements each you would get 6 results (2x3), 3 copies of each SynonymMapping entity. So the easiest workaround is to wrap results in a Set thereby ensuring they're unique.
你得到重复的原因是因为 Hibernate 在内部连接了你的根表和集合表。请注意,它们确实是重复的,例如,对于具有 3 个集合元素的 2 个 SynonymMappings,您将获得 6 个结果 (2x3),每个 SynonymMapping 实体的 3 个副本。因此,最简单的解决方法是将结果包装在 Set 中,从而确保它们是唯一的。
回答by Arthur Ronald
You could use a SELECT DISTINCT (Hibernate Query Language) clause as follows
您可以使用 SELECT DISTINCT (Hibernate Query Language) 子句如下
SELECT DISTINCT synonym FROM SynonymMapping synonym LEFT JOIN FETCH synonym.values
DISTINCT clause removes duplicate references in Hibernate.
DISTINCT 子句删除 Hibernate 中的重复引用。
Although both component and value-type collection has its lifecycle bound to the owning entity class, you should declare them in select clause in order to retrieve them. (LEFT JOIN FETCH synonym.values)
尽管组件和值类型集合的生命周期都绑定到拥有的实体类,但您应该在 select 子句中声明它们以便检索它们。(LEFT JOIN FETCH 同义词.values)
ChssPly76's answer is another approach, but does not forget override equals and hashcode method according to Set semantic
ChssPly76 的答案是另一种方法,但不会忘记根据 Set 语义覆盖 equals 和 hashcode 方法
regards,
问候,
回答by Arthur Ronald
I stepped into the same problem - when you set the FetchType.EAGER for a @CollectionOfElements, the Hibernate tries to get everything in one shot, i.e. using one single query for each entry of element linked to a "master" object. This problem can be successfully solved at a cost of N+1 query, if you add the @Fetch (FetchMode.SELECT) annotation to your collection. In my case I wanted to have a MediaObject entity with a collection of its metadata items (video codec, audio codec, sizes, etc.). The mapping for a metadataItems collection looks as follows:
我遇到了同样的问题 - 当您为 @CollectionOfElements 设置 FetchType.EAGER 时,Hibernate 会尝试一次性获取所有内容,即对链接到“主”对象的每个元素条目使用一个查询。如果在集合中添加@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>();
回答by Raja Anbazhagan
I have faced this problem and I solved it using
我遇到了这个问题,我使用解决了它
criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
This clears out the duplicates which are caused by the join made to the child tables.
这会清除由对子表进行的连接引起的重复项。
回答by Grigory Kislin
Instead of FetchMode.SELECT
with N+1 queries it is better using BatchSize
e.q. @BatchSize(size = 200)
.
与其FetchMode.SELECT
使用 N+1 查询,不如使用BatchSize
eq @BatchSize(size = 200)
。
DISTINCT
and Criteria.DISTINCT_ROOT_ENTITY
doesn't help, if you have to fetch more than 1 association. For this case see other solutions: https://stackoverflow.com/a/46013654/548473
DISTINCT
并且Criteria.DISTINCT_ROOT_ENTITY
没有帮助,如果您必须获取超过 1 个关联。对于这种情况,请参阅其他解决方案:https: //stackoverflow.com/a/46013654/548473
回答by Rahul Gangahar
I have achieved it via simply add
我通过简单地添加实现了它
session.createCriteria(ModelClass.class).setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
This help to remove duplicate.
这有助于删除重复项。