29

Is anyone aware of the validity of Hibernate's Criteria.list() and Query.list() methods returning multiple occurrences of the same entity?

Occasionally I find when using the Criteria API, that changing the default fetch strategy in my class mapping definition (from "select" to "join") can sometimes affect how many references to the same entity can appear in the resulting output of list(), and I'm unsure whether to treat this as a bug or not. The javadoc does not define it, it simply says "The list of matched query results." (thanks guys).

If this is expected and normal behaviour, then I can de-dup the list myself, that's not a problem, but if it's a bug, then I would prefer to avoid it, rather than de-dup the results and try to ignore it.

Anyone got any experience of this?

skaffman
  • 381,978
  • 94
  • 789
  • 754

4 Answers4

23

Yes, getting duplicates is perfectly possible if you construct your queries so that this can happen. See for example Hibernate CollectionOfElements EAGER fetch duplicates elements

Community
  • 1
  • 1
Eemeli Kantola
  • 4,975
  • 6
  • 32
  • 41
  • 6
    +1. How can I not upvote someone linking to my answer? :-) Seriously, however - yes, Hibernate may return duplicates when more than one "to-many" association is either declared with eager fetch or retrieved using join fetch within the same query. Look at the note at the bottom of 14.3: http://docs.jboss.org/hibernate/stable/core/reference/en/html/queryhql.html#queryhql-joins – ChssPly76 Oct 13 '09 at 15:53
  • Thanks for the doc link, I knew it had to be in there somewhere – skaffman Oct 13 '09 at 16:02
  • @ChssPly76 The link is broken! – Champ Jul 08 '13 at 12:14
  • 3
    updated link: http://docs.jboss.org/hibernate/orm/4.2/manual/en-US/html/ch16.html#queryhql-joins – black666 Nov 15 '13 at 21:40
6

I also started noticing this behavior in my Java API as it started to grow. Glad there is an easy way to prevent it. Out of practice I've started out appending:

.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY)

To all of my criteria that return a list. For example:

List<PaymentTypeAccountEntity> paymentTypeAccounts = criteria()
  .setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY)
  .list();
Sam Berry
  • 6,195
  • 5
  • 35
  • 52
4

If you have an object which has a list of sub objects on it, and your criteria joins the two tables together, you could potentially get duplicates of the main object.

One way to ensure that you don't get duplicates is to use a DistinctRootEntityResultTransformer. The main drawback to this is if you are using result set buffering/row counting. The two don't work together.

Mike
  • 751
  • 6
  • 16
0

I had the exact same issue with Criteria API. The simple solution for me was to set distinct to true on the query like

CriteriaQuery<Foo> query = criteriaBuilder.createQuery(Foo.class);
query.distinct(true);

Another possible option that came to my mind before would be to simply pass the resulting list to a Set which will also by definition have just an object's single instance.

hecko84
  • 949
  • 1
  • 12
  • 26