1

I have two entities: User and Address. User has an "address" property:

@OneToMany (mappedBy="user", fetch=FetchType.EAGER) 
public List<Adress> getAddress() {
    return this.address;
}
public void setAddress(List<Adress> address) {
    this.address= address;
} 

The fetch type is eager as shown above.

I'm trying to use Criteria in order to get a list of Users as follows:

List<User> p=session.createCriteria(User.class).list();

Unfortunately it gets repeated users if a user has more than one address. With eager fetching turned off, it doesn't get duplicates. How can I get a list of users without repeated items using Criteria?

Ryan Stewart
  • 126,015
  • 21
  • 180
  • 199
cracq
  • 81
  • 1
  • 9

2 Answers2

3

It's discouraged to map *-to-many relationships as FetchType.EAGER. If you need eager fetching, you do it on a per-query basis. That being said, when you use FetchType.EAGER, Hibernate switches to an outer join select, as that's what makes the most sense for situations where eager fetching is really relevant. An outer join, of course, causes the behavior you're seeing. I'd recommend you remove the FetchType.EAGER and write an appropriate query to fetch the data you want.

The less-recommended alternative would be to add @Fetch(FetchMode.SELECT) to your mapping. This means every time you load a user, it will issue two selects: one for the user and one for the addresses. This is essentially the same as if you were using a lazy relationship anyway, so what's the point?

Ryan Stewart
  • 126,015
  • 21
  • 180
  • 199
  • I need eager fetching in almost all methods in which I get the users list, otherwise, i get many lazy no session open... exceptions. Anyway, even though I'd do it on a per-query basis as you say, the problem still persist. – cracq Jul 19 '11 at 04:54
  • 1
    @cracq: Eager fetching is exactly the wrong solution to LazyInitializationExceptions. See [my answer here](http://stackoverflow.com/questions/6709750/proper-usage-of-spring-mvc-3-with-hibernate-spring-orm/6710885#6710885) for how to fix those. Look under "Session Management". You might also find [this answer](http://stackoverflow.com/questions/6722158/best-way-to-handle-hibernate-sessions-in-a-layered-spring-mvc-web-application/6723767#6723767) useful. – Ryan Stewart Jul 19 '11 at 05:03
  • Ok, thanks, anyway, I could do something like that instead of use eager fetching: `for(User u:listofusers){ u.getListAddress.size(); }` I really works, but I don't want to go through the entire collection whenever i want to initialize the user address list.. There is also a method Hibernate.initialize() for this purpose, but it doesn't work for me. I guess this is not a good solution, am I right? – cracq Jul 19 '11 at 05:12
  • @cracq: Right, by far the best solution is to use the [open session in view pattern](http://community.jboss.org/wiki/OpenSessionInView) and let lazy relationships take care of themselves. Fetching strategies are meant to be used in queries for [performance tuning](http://docs.jboss.org/hibernate/core/3.5/reference/en/html/performance.html), not for this. – Ryan Stewart Jul 19 '11 at 05:17
0

Set mycrit.setFetchMode("address", FetchMode.SELECT). Then it runs a separate select for the association and you won't get dupes.

atrain
  • 9,139
  • 1
  • 36
  • 40