@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 имеет смысл в моем случае, но не ценой обзора всех реализаций уровня доступа к данным.
Что делать?