Hibernate CollectionOfElements EAGER fetch duplicates elements

Viewed 31639

I have a class called SynonymMapping which has a collection of values mapped as a 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.

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.

Can anyone tell me why an eager fetch is duplicating the objects?

Thanks.

6 Answers

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).

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.

You could use a SELECT DISTINCT (Hibernate Query Language) clause as follows

SELECT DISTINCT synonym FROM SynonymMapping synonym LEFT JOIN FETCH synonym.values

DISTINCT clause removes duplicate references in 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)

ChssPly76's answer is another approach, but does not forget override equals and hashcode method according to Set semantic

regards,

I have achieved it via simply add

session.createCriteria(ModelClass.class).setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);

This help to remove duplicate.

Related