@ElementCollection Сохранение Java (Hibernate) вызывает загрузку повторяющихся экземпляров

При использовании @ElementCollection загружается все, загружая несколько экземпляров объекта. Более конкретно, он загружает один экземпляр для каждого элемента в collectionOfStrings.

Например, база данных с единственным экземпляром MyClass с collectionOfStrings.size() == 4, вызов для загрузки всех значений MyClass возвращает список размером 4 (все тот же объект) вместо всего лишь одного объекта.

Есть ли простой и простой способ разрешения этого или ожидаемое поведение?

// Parent class is a @MappedSuperclass which may or may not be relevant to the issue
@Entity
public class MyClass extends ParentClass {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private long id;

    @ElementCollection(fetch=FetchType.EAGER)
    @IndexColumn(name="indexColumn")
    private List<String> collectionOfStrings;

    // other instance variables, constructors, getters, setters, toString, hashcode and equals
}

public class MyClassDAO_Hibernate extends GenericHibernateDAO<MyClass, Long> implements MyClassDAO {

    @Override
    public List<MyClass> loadAll() {
        List<MyClass> entityList = null;
        Session session = getSession();
        Transaction trans = session.beginTransaction();
        entityList = findByCriteria(session);
        trans.commit();
        return entityList;
    }

}

protected List<T> findByCriteria(Session session, Criterion... criterion) {
    Criteria crit = session.createCriteria(getPersistentClass());
    for (Criterion c : criterion) {
        crit.add(c);
    }
    return crit.list();
}

MyClassDAO myClassDAO = new MyClassDAO_Hibernate(); // in reality, implementation type is determined with a Factory
...
List<MyClass> myClassInstances = myClassDAO.loadAll();

Спасибо, HeavyE

Изменить: добавлен вызов findByCriteria.

Ответ 1

Я не уверен, является ли это ошибкой или законным поведением, но его можно устранить, применив трансформатор результатов DISTINCT_ROOT_ENTITY:

protected List<T> findByCriteria(Session session, Criterion... criterion) {
    Criteria crit = session.createCriteria(getPersistentClass());
    for (Criterion c : criterion) {
        crit.add(c);
    }
    crit.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
    return crit.list();
}

Ответ 2

Это правильное поведение List. Список разрешает дублирование объектов, и именно по этой причине вам нужен индексный столбец.

Это общий тип коллекции, который можно отобразить с помощью Hibernate:

Установить - это коллекция, в которой ни один элемент не встречается более одного раза. Это самый распространенный тип постоянной коллекции, по моему опыту.

Сумка представляет собой коллекцию, в которой элементы могут встречаться более одного раза: они очень неэффективны, потому что hibernate не может определить, находятся ли элементы, которые вы вставляете в нее, те же, что и те, которые уже в ней (при условии, что они равно), поэтому он должен удалить всю коллекцию и снова сохранить ее из памяти.

Список - это индексированный пакет. Индекс позволяет hibernate знать, является ли конкретный объект в памяти тем же самым, что и для равного объекта на БД, поэтому полное удаление/повторная установка не требуется.

Карта похожа на список, за исключением того, что индекс не должен быть вычислимым (обычно последовательным) целым числом, он может быть любым, даже другим объектом.

Итак, в вашем случае я рекомендую вам использовать Set.

Ответ 3

Это наблюдается только тогда, когда коллекция с нетерпением ходит. Hibernate преобразует это сопоставление аннотаций в внешний запрос соединения, который вызывает множественный список корневых элементов для каждого связанного элемента collectionOfString.

Посмотрите на билет HHH-6783 в отслеживателе проблем Hibernate ORM для этой точной проблемы. И, по-видимому, никакого решения.: - (

Здесь также предоставляется ссылка на часто задаваемые вопросы о спящем режиме, которые входят в проблемы с внешним соединением.

Я имею дело с одной и той же проблемой. Использование @ElementCollection имеет смысл в моем случае, но не ценой обзора всех реализаций уровня доступа к данным. Что делать?