Is it possible to tell hibernate to use LinkedHashSet as a underlying set for PersistentSet without OrderBy annotation

Hi, I am ordering one to many relation with querydsl cause i don’t want to use order by default, only when its needed. So the problim is - because the hibernate uses hash set for underlying set of PersistentSet order is not saved after fetch from repository even there is order by clause in generated sql. So is there any solution to tell hibernate to use LinkedHashSet for PersistentSet without using @OrderBy annotation cause with @Orderby order is deafult when fetching parent entity?

You can use a custom UserCollectionType implementation, and then annotate your collection as @CollectionType( type = MyUserCollectionType.class ). You can also use the the @CollectionTypeRegistration to register the type easily and always use it when mapping attributes of a certain collection interface / class.

I tried like this

package com.isc.fdesig.configuration;

import org.hibernate.collection.spi.PersistentSet;
import org.hibernate.collection.spi.PersistentCollection;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.metamodel.CollectionClassification;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.usertype.UserCollectionType;

import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.Map;

public class CustomOrderedSetType implements UserCollectionType {

    @Override
    public CollectionClassification getClassification() {
        return CollectionClassification.ORDERED_SET; // Define como un conjunto ordenado
    }

    @Override
    public Class<?> getCollectionClass() {
        return LinkedHashSet.class; // Usa LinkedHashSet como colección subyacente
    }

    @Override
    public PersistentCollection<?> instantiate(SharedSessionContractImplementor session, CollectionPersister persister) {
        // Usa un PersistentSet de Hibernate con LinkedHashSet como colección subyacente
        return new PersistentSet<>(session, new LinkedHashSet<>());
    }

    @Override
    public PersistentCollection<?> wrap(SharedSessionContractImplementor session, Object collection) {
        if (collection instanceof LinkedHashSet) {
            return new PersistentSet<>(session, (LinkedHashSet<?>) collection);
        }
        throw new IllegalArgumentException("Collection must be an instance of LinkedHashSet");
    }

    @Override
    public Iterator<?> getElementsIterator(Object collection) {
        if (collection instanceof PersistentSet) {
            return ((PersistentSet<?>) collection).iterator();
        }
        if (collection instanceof LinkedHashSet) {
            return ((LinkedHashSet<?>) collection).iterator();
        }
        throw new IllegalArgumentException("Collection must be an instance of PersistentSet or LinkedHashSet");
    }

    @Override
    public boolean contains(Object collection, Object entity) {
        if (collection instanceof PersistentSet) {
            return ((PersistentSet<?>) collection).contains(entity);
        }
        if (collection instanceof LinkedHashSet) {
            return ((LinkedHashSet<?>) collection).contains(entity);
        }
        throw new IllegalArgumentException("Collection must be an instance of PersistentSet or LinkedHashSet");
    }

    @Override
    public Object indexOf(Object collection, Object entity) {
        throw new UnsupportedOperationException("OrderedSetType does not support indexing.");
    }

    @Override
    public Object replaceElements(Object original, Object target, CollectionPersister persister, Object owner, Map copyCache, SharedSessionContractImplementor session) {
        if (!(target instanceof PersistentSet)) {
            throw new IllegalArgumentException("Target must be an instance of PersistentSet");
        }
        ((PersistentSet<?>) target).clear();
        if (original instanceof PersistentSet) {
            ((PersistentSet<?>) target).addAll((PersistentSet) original);
        } else if (original instanceof LinkedHashSet) {
            ((PersistentSet<?>) target).addAll((LinkedHashSet) original);
        } else {
            throw new IllegalArgumentException("Original must be an instance of PersistentSet or LinkedHashSet");
        }
        return target;
    }

    @Override
    public LinkedHashSet<?> instantiate(int anticipatedSize) {
        return anticipatedSize > 0
                ? new LinkedHashSet<>(anticipatedSize) // LinkedHashSet con capacidad anticipada
                : new LinkedHashSet<>(); // LinkedHashSet vacío
    }
}

It works well when I rescue the entities, but does not work well when you try to update an entity, it gives errors of unmanaged entities, in addition to other errors that I have been “fixing”.

The idea is the same, to be able to use my own Specification with its query.orderBy and that my Sets use LinkedHashSet so that the ordering works but without using @OrderBy.

@vlad or someone else could you help me with this, please?

I’m using Spring boot 3.3.2