原文链接:https://doctorjw.wordpress.com/2012/01/11/hibernate-collections-and-duplicate-objects/
It’s interesting that Hibernate doesn’t take care of this under the covers, but forces developers to realize they may get duplicate objects under some circumstances.
The story: at work yesterday, a buddy and I started working on an odd defect. When our users added a particular type of object (Waste), it would show up in the list of existing objects as 2 Waste entries. Deleting one of them resulted in both going away; a quick check of the db indicated that yes, indeed, when we added an item, just one was created in the db. Clearly, either the view was showing a duplicate, or somewhere in the business layer, the item was being replicated. It didn’t take long to isolate the issue to the retrieval of the Waste items from the database, and to tie the appearance of the issue to a particular change in our Waste class.
@OneToMany(mappedBy = "waste", fetch = FetchType.LAZY, orphanRemoval = true) @org.hibernate.annotations.Cascade({org.hibernate.annotations.CascadeType.ALL}) private List<WasteDetail> details = new ArrayList<WasteDetail>();
was changed to
@OneToMany(mappedBy = "waste", fetch = FetchType.EAGER, orphanRemoval = true) @org.hibernate.annotations.Cascade({org.hibernate.annotations.CascadeType.ALL}) private List<WasteDetail> details = new ArrayList<WasteDetail>();
Changing from FetchType.LAZY to FetchType.EAGER apparently has Hibernate attempting to retrieve all items within the collection with a single fetch, using an outer join. Within our dao, we have
Criteria c = getSession().createCriteria(Waste.class); c.add(Restrictions.eq("store.idoreId)); c.addOrder(Order.desc("wasteDateList<Waste> retVal = c.list();
The retrieval of a list of Waste items, with the collection inside each Waste, results in a cartesian product through the outer join — so a Waste object with 2 WasteDetails will show up twice in the list; 3 WasteDetails will net you 3 Waste objects …
A quick bit of Google magic led me to this post, which further pointed to the Hibernate FAQ; of specific use was this entry. Several techniques for eliminating the duplicates are documented; one that we’ve (apparently) used on this project in the past is not, however.
What we’ve used before is to add the annotation @Fetch(FetchMode.SUBSELECT) (though FetchMode.SELECT will also work) on the collection in the domain object. The collection with it’s annotations then becomes:
@OneToMany(mappedBy = "waste", fetch = FetchType.EAGER, orphanRemoval = true) @org.hibernate.annotations.Cascade({org.hibernate.annotations.CascadeType.ALL}) @Fetch(FetchMode.SUBSELECT) private List<WasteDetail> details = new ArrayList<WasteDetail>();
This forces hibernate to not use the Join, and instead sends multiple sql calls to the db to retrieve the data.
If you’re not concerned about performance, using FetchMode.SUBSELECT or FetchMode.SELECT on the domain class will work, eliminating the duplicates.
Alternatively, if you’re concerned about performance and want the select to the database to happen in a single call via the join, then use one of the techniques in the hibernate FAQ. I would lean towards adding setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY)
to the Criteria, as it’s pretty explicit (unlike using a LinkedHashSet). For example, this:
Criteria c = getSession().createCriteria(Waste.class); c.add(Restrictions.eq("store.idoreId)); c.addOrder(Order.desc("wasteDatec.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY); List<Waste> retVal = c.list();
also works just fine, and preserves the Join nature of the select generated by Hibernate. The issue I have with the techniques in the FAQ are that they are not directly on the domain class, but on the DAO. Not a huge deal, I suppose, as all operations affecting this object should go through the Waste dao … but … what happens if I persist another object that contains a collection of Waste items? Hmmm…..
相关推荐
Using LINQ to Objects, .NET developers can write queries over object collections with the same deep functionality that was once available only with SQL and relational databases. Now, for the first ...
In the realm of iOS development, collections play a crucial role in organizing and managing data. The Apple documentation on collections provides a comprehensive overview of various types of ...
Java程序设计英文版课件:ch11 Collections of Objects.ppt
12. **commons-collections4-4.x.jar**(可选):提供了一些实用的集合类,某些版本的Hibernate可能依赖此库。 13. **jandex-2.x.x.Final.jar**(可选):用于元数据索引,提高Hibernate的性能。 在实际开发中,...
该文件里包含两个.jar包: collections-generic-4.01.jar和looks-2.1.4.jar, 引入collections-generic-4.01.jar: 右击工程--》Build path ——》Add External JAR-->选中collections-generic-4.01.jar --》OK 在源...
1.2.6. Loading and storing objects 1.3. Part 2 - Mapping associations 1.3.1. Mapping the Person class 1.3.2. A unidirectional Set-based association 1.3.3. Working the association 1.3.4. Collection of ...
commons-collections-20040616.jar, commons-collections-3.2-osgi.jar, commons-collections-3.2-sources.jar, commons-collections-3.2.1.jar, commons-collections-3.2.2-javadoc.jar, commons-collections-3.2.2...
collections, and complex class associations. Finally, we discuss integration with legacy database schemas and some mapping strategies that are especially tricky. Part 3, “Transactional data ...
* Support for fine-grained object models - a rich variety of mappings for collections and dependent objects * No build-time bytecode enhancement - there's no extra code generation or bytecode ...
* Support for fine-grained object models - a rich variety of mappings for collections and dependent objects * No build-time bytecode enhancement - there's no extra code generation or bytecode ...
* Support for fine-grained object models - a rich variety of mappings for collections and dependent objects * No build-time bytecode enhancement - there's no extra code generation or bytecode ...
6.2.4. 值集合于多对多关联(Collections of values and many-to-many associations) 6.2.5. 一对多关联(One-to-many Associations) 6.3. 高级集合映射(Advanced collection mappings) 6.3.1. 有序集合...
- **Loading and Storing Objects**: Finally, you'll learn how to load objects from the database into Java instances and persist new or updated Java objects back to the database. #### Mapping ...
// getters and setters } ``` 4. **配置映射文件**(可选):如果选择使用 XML 映射文件,创建 `User.hbm.xml`,指定对象与表的映射关系。 5. **初始化 SessionFactory**:在应用程序启动时,根据配置文件创建...
6.2.4. 值集合于多对多关联(Collections of values and many-to-many associations) 6.2.5. 一对多关联(One-to-many Associations) 6.3. 高级集合映射(Advanced collection mappings) 6.3.1. 有序集合...
6.2.4. 值集合于多对多关联(Collections of values and many-to-many associations) 6.2.5. 一对多关联(One-to-many Associations) 6.3. 高级集合映射(Advanced collection mappings) 6.3.1. 有序集合...