Why are object references duplicated for each row of ResultSet?

For example, given this data model:

@Entity
public class Library {
	@Id
	private Long id;
	
	@OneToMany
	private List<Book> books = new ArrayList<>();
	
	@OneToMany
	private Set<Movie> movies = new HashSet<>();
}

This JPQL:

SELECT l FROM Library AS l LEFT JOIN FETCH l.books LEFT JOIN FETCH l.movies WHERE l.id = :id

will return 10 rows if there are 2 books and 5 movies associated with that Library. The session will create a single Library instance, but return 10 duplicate references. Likewise there will be 2 Book instances, with 5 duplicate references to each one in the books collection. movies will not have duplicates because of Set’s inherent filtering.

I’m curious why Hibernate behaves like this instead of intuitively “boiling” down to unique references. Is this because of a technical reason, or is there a use-case which requires duplicates?

There are cases where it is impossible to eliminate duplicates when a bag join is involved, since bags are unordered and allow duplicates. So Hibernate doesn’t try to be smart and cause you headaches in certain scenarios, but instead just returns you the same cardinality as the JDBC result set. You can tell Hibernate to return unique objects which works by using DISTINCT. Note that the DISTINCT keyword is not necessarily passed to the SQL if you configure this a hint as outlined in the documentation: Hibernate ORM 5.4.29.Final User Guide