Почему я должен изгнать свою сущность из общего кэша EclipseLink, прежде чем запросы с графом сущностей загрузят мои ленивые свойства? - PullRequest
0 голосов
/ 11 января 2020

Перед обновлением сущности в моем приложении Jakarta EE, работающем на GlassFi sh 5.1.0 с EclipseLink 2.7.4 и Derby 10.14.2.0, я сравниваю обновленную сущность с сохраненной сущностью и документирую изменения. Недавно я заметил, что мой код сравнения не работает со свойствами отношений @OneToMany и свойствами @ElementCollection, и я отслеживал проблему с отложенной загрузкой свойств @OneToMany и @ElementCollection. Я смог разрешить использование атрибута fetch следующим образом:

Fetch Eager Entity

@Entity
public class Container implements Serializable {

    @OneToMany(mappedBy = "container", fetch = FetchType.EAGER)
    private List<AssetSerial> assets;

    @ElementCollection (fetch = FetchType.EAGER)
    private List<Reference> references;

Я не был полностью доволен этим решением, потому что предположил что разработчики по умолчанию установили эти типы отношений на ленивую загрузку, поэтому я продолжил исследования и был рад найти много ссылок на JPA Entity Graphs. Я немедленно создаю следующий код, чтобы заставить EclipseLink инициализировать мои свойства отложенной загрузки перед документированием изменений сущности.

Entity Graph Entity

@Entity
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
@NamedEntityGraph(
    name = "Container.eager",
    attributeNodes = {
            @NamedAttributeNode("assets"),
            @NamedAttributeNode("references") })
public class Container implements Serializable {

Entity Manager Инициализация

@PersistenceContext(unitName = "MYPU")
private EntityManager em;

Метод поиска, который работает только один раз для объекта

Map<String, Object> props = new HashMap<String, Object>();
props.put("javax.persistence.loadgraph", em.getEntityGraph("Container.eager"));

Container managedContainer = em.find(Container.class, updatedContainer.getId(), props);

PersistenceUnitUtil tester = em.getEntityManagerFactory().getPersistenceUnitUtil();

logger.debug("Assets: {}", tester.isLoaded(managedContainer, "assets"));
logger.debug("References: {}", tester.isLoaded(managedContainer, "references"));

К сожалению, тестовые методы isLoaded возвращают true только при первом вызове метод find для указанной сущности c. Второй и последующие моменты времени isLoaded возвращает false. Я боролся с этой проблемой в течение многих часов и решил, что эта проблема заключалась в том, что общий кэш EclipseLink не учитывал подсказку графа сущностей, которую я передавал методу find. Я решил проблему, высвободив сущность из кэша непосредственно перед вызовом поиска, как показано ниже.

Метод поиска, который работает

em.getEntityManagerFactory().getCache().evict(Container.class, updatedContainer.getId());

Map<String, Object> props = new HashMap<String, Object>();
props.put("javax.persistence.loadgraph", em.getEntityGraph("Container.eager"));

Container managedContainer = em.find(Container.class, updatedContainer.getId(), props);

PersistenceUnitUtil tester = em.getEntityManagerFactory().getPersistenceUnitUtil();

logger.debug("Assets: {}", tester.isLoaded(managedContainer, "assets"));
logger.debug("References: {}", tester.isLoaded(managedContainer, "references"));

Теперь тест isLoaded всегда возвращает true, и я могу документировать все изменения в обновленном объекте.

Итак, у меня есть следующие вопросы:

  • Почему EclipseLink не учитывает мой граф сущностей?
  • Буду ли я сталкиваться с проблемами, вручную выселяющими мою сущность из кеш?
  • Есть ли лучший способ заставить EclipseLink инициализировать мои свойства отложенной загрузки?
...