2015-12-10 6 views
5

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

У меня есть два объекта с отношением @OneToMany (один человек имеет много адресов), который лениво загружен.

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

Я не понимаю, почему это работает. Я бы ожидал какого-то исключения. Я читал немало о jpa и т. П. В последние дни (то есть this link), но все указывало на то, что он не должен работать.

Может кто-нибудь объяснить, почему это работает?

@Stateless 
public class Test { 
    @PersistenceContext(unitName="TestPU") EntityManager em; 

    public void test() { 
     Person person = em.find(Person.class, 1); 

     System.out.println(person); 

     System.out.println("em.contains(person): " + em.contains(person); 

     em.detach(person); 

     System.out.println("em.contains(person): " + em.contains(person); 

     person.getAddresses().size(); 

     System.out.println("em.contains(person): " + em.contains(person); 

     System.out.println(person); 

    } 
} 

В результате журнал будет

DEBUG: SELECT ... from PERSON WHERE (id = ?) 
Person{id=1, name=Test, addresses={IndirectList: not instantiated}} 
em.contains(person): true 
em.contains(person): false 
DEBUG: SELECT ... FROM ADDRESSES where (address_fk = ?) 
em.contains(person): false 
Person{id=1, name=Test, addresses={[Address{id=10, city=Testcity}]}} 
+3

потому что с EclipseLink они на самом деле не «отделяют» объекты от того, как намеревается спецификация JPA (т.е. отсоединяется от БД), поэтому они сохраняют информацию о подключении ... следовательно, она извлекает поле (хотя оно не должно если действительно «отделился»). Если вы выполняли ту же операцию с другими поставщиками JPA, они обычно генерировали исключение, если поле не было отключено. –

+0

Вы можете проверить, правильно ли удален объект, вызвав [em.contains] (http://docs.oracle.com/javaee/6/api/javax/persistence/EntityManager.html#contains%28java.lang.Object % 29) –

ответ

1

Как описано here открепления удаляет Субъекта из контекста так, чтобы она больше не удалось. Поскольку контекст по-прежнему доступен, но при необходимости могут быть извлечены неиспользуемые ленивые коллекции, и EclipseLink считает это более ценным, чем исключение. Это считается особенностью EclipseLink и разрешено спецификацией JPA, несмотря на то, что другие поставщики не разрешают поведение по умолчанию.

+0

Спасибо за разъяснение. Хотя я не уверен, что спецификация JPA позволяет это beahviour. Я не эксперт по чтению спецификаций, но насколько я понимаю, следующая цитата запрещает это поведение. 'Доступное состояние связанного экземпляра МОЖЕТ ТОЛЬКО быть безопасным, если соответствующий экземпляр доступен. '(JSR 338, раздел 3.2. 7 Отдельные объекты) – Filou

+0

Указывает, что поведение не определено, а не требует исключения, а EclipseLink - эталонная реализация спецификации. Невозможно получить доступ к отношениям после этого, поскольку сущности могут быть сериализованы в любое время, нарушая соединение с контекстом (даже если оно все еще открыто). – Chris

+0

Вы правы, это не запрещено. Нет, не стоит. Мне просто нужно немного больше привыкнуть к чтению спецификаций. Еще раз спасибо за разъяснение! – Filou