Существует метод, который возвращает объект из базы данных JPA. У этого объекта есть список для других объектов, тип выборки LAZY. Когда я хочу, чтобы добавить объект к этому списку я получил исключение:JPA lazy fetch list вызывает запросы SELECT в setter
Caused by: Exception [EclipseLink-7242] (Eclipse Persistence Services - 2.5.2.v20140319-9ad6abd): org.eclipse.persistence.exceptions.ValidationException
Exception Description: An attempt was made to traverse a relationship using indirection that had a null Session. This often occurs when an entity with an uninstantiated LAZY relationship is serialized and that lazy relationship is traversed after serialization. To avoid this issue, instantiate the LAZY relationship prior to serialization.
Так что для того, чтобы преодолеть это я могу инициализировать этот список, выполнив .size()
на него. Дело в том, что мне действительно не нужны эти объекты для извлечения из базы данных, поэтому я хотел бы сделать что-то вроде этого: fetchedEntity.setMyLazyFetchList(new ArrayList<>());
, который отлично работает. Я могу получить доступ к моему списку, но проблема следующая: set method вызывает те же запросы на выбор, что и fetchedEntity.getMyLazyFetchList().size()
. Эти запросы бесполезны, поскольку я устанавливаю значение для нового списка, поэтому почему они вызываются?
Метод выборка лицо
public Competitor findAndInitializeEmptyGroups(Integer idCompetitor) {
Competitor entity = em.find(Competitor.class, idCompetitor);
System.out.println("Before set ");
entity.setGroupCompetitorList(new ArrayList<>());
System.out.print("After set lazy list size ");
System.out.print(entity.getGroupCompetitorList().size());
return entity;
}
Ленивый выборки список полей в сущности (Конкурент)
@OneToMany(mappedBy = "idCompetitor")
private List<GroupCompetitor> groupCompetitorList = new ArrayList<>();
Второе поле конечного отношения (GroupCompetitor)
@JoinColumn(name = "id_competitor", referencedColumnName = "id_competitor")
@ManyToOne(optional = false)
private Competitor idCompetitor;
Что журналы говорят:
Info: Before set
Fine: SELECT id_group_competitor, id_competitor, id_group_details FROM group_competitor WHERE (id_competitor = ?)
bind => [43]
Fine: SELECT id_group_details, end_date, start_date, version, id_competition, id_group_name FROM group_details WHERE (id_group_details = ?)
bind => [241]
...
many more SELECTs
Info: After set lazy list size
Info: 0
После замены линии
entity.setGroupCompetitorList(new ArrayList<>());
с
entity.getGroupCompetitorList().size();
И бревен (они же, кроме списка теперь состоит из принесенных лиц) :
Info: Before set
Fine: SELECT id_group_competitor, id_competitor, id_group_details FROM group_competitor WHERE (id_competitor = ?)
bind => [43]
Fine: SELECT id_group_details, end_date, start_date, version, id_competition, id_group_name FROM group_details WHERE (id_group_details = ?)
bind => [241]
...
many more SELECTs
Info: After set lazy list size
Info: 44
Так что мой вопрос: почему SELECT
запросы вызываются, когда я делаю entity.setGroupCompetitorList(new ArrayList<>());
? Я не хочу, чтобы они были по соображениям производительности. Есть ли способ устранить эту проблему или что именно вызывает это поведение?
Использование:
- EclipseLink JPA 2.1
- GlassFish 4.1
- Java 8
Вы изменяете/получаете доступ к списку, который заставляет запрос в JPA отслеживать любые изменения, внесенные вами в объект. Eclipselink использует ткачество, которое помогает отслеживать изменения, и поэтому, если вы хотите обойти инициирование отношения, вам может понадобиться обойти его плетение. см. http://www.eclipse.org/eclipselink/documentation/2.5/concepts/app_dev007.htm и https://wiki.eclipse.org/EclipseLink/UserGuide/JPA/Advanced_JPA_Development/Performance/Weaving/Disabling_Weaving_with_Persistence_Unit_Properties – Chris
Установка '< свойство name = "eclipselink.weaving.changetracking" value = "false" /> 'или используя' @ChangeTracking (DEFERRED) 'в сущности, вызвало, что эти запросы SELECT не вызывались во время' set() ', но я заметил, что они вызываются во время следующего EntityManager 'flush()', поэтому производительность не улучшилась, но спасибо за ссылки, они помогли мне понять некоторые вещи. – Geinmachi
Вы пытаетесь заменить список? Поставщик JPA нуждается в этом списке, чтобы узнать, какие ссылки удалить в базе данных при слиянии с ним. Если это так, вы хотите использовать функцию ткачества и отслеживания изменений. EclipseLink может отслеживать дополнения к спискам без необходимости извлекать полный список, если отслеживание изменений включено, если объект привязан к контексту. Если вам нужно сериализовать объект, его нужно будет предварительно запрограммировать или вы не сможете получить доступ к коллекции. – Chris