Как проверить, инициализирована ли ленивая загруженная коллекция JPA?
У меня есть служба, которая получает объект JPA из внешнего кода. В этой службе я хотел бы выполнить итерацию по лениво загруженной коллекции, которая является атрибутом этого объекта, чтобы увидеть, добавил ли клиент что-то к ней относительно текущей версии в БД.
Однако клиент, возможно, никогда не касался коллекции, поэтому он все еще не инициализирован. Это приводит к хорошо известному
org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.example.SomeEntity.
Конечно, если клиент никогда не касался коллекции, мой сервис не должен проверять его на предмет возможных изменений. Дело в том, что я не могу найти способ проверить, инициализирована ли коллекция или нет. Наверное, я мог бы называть size()
на нем, и если он выбрасывает LazyInitializationException
, я бы знал, но я стараюсь не зависеть от таких шаблонов.
Есть ли какой-нибудь метод isInitialized()
?
Ответы
Ответ 1
Используете ли вы JPA2?
PersistenceUnitUtil
имеет два метода, которые могут использоваться для определения состояния загрузки объекта.
например. существует двунаправленная связь OneToMany/ManyToOne между Организацией и пользователем.
public void test() {
EntityManager em = entityManagerFactory.createEntityManager();
PersistenceUnitUtil unitUtil =
em.getEntityManagerFactory().getPersistenceUnitUtil();
em.getTransaction().begin();
Organization org = em.find(Organization.class, 1);
em.getTransaction().commit();
Assert.assertTrue(unitUtil.isLoaded(org));
// users is a field (Set of User) defined in Organization entity
Assert.assertFalse(unitUtil.isLoaded(org, "users"));
initializeCollection(org.getUsers());
Assert.assertTrue(unitUtil.isLoaded(org, "users"));
for(User user : org.getUsers()) {
Assert.assertTrue(unitUtil.isLoaded(user));
Assert.assertTrue(unitUtil.isLoaded(user.getOrganization()));
}
}
private void initializeCollection(Collection<?> collection) {
// works with Hibernate EM 3.6.1-SNAPSHOT
if(collection == null) {
return;
}
collection.iterator().hasNext();
}
Ответ 2
org.hibernate.Hibernate.isInitialized(..)
Я не знаю стандартного решения JPA. Но если вы хотите фактически инициализировать коллекции, вы можете создать метод утилиты и перебрать их (достаточно только одной итерации).
Ответ 3
Как указывает другой плакат, у Hibernate есть метод для этого. Однако для чистого JPA решения нет.
Ответ 4
Для eclipselink
пользователи бросают коллекцию, к которой вы пытаетесь получить доступ к org.eclipse.persistence.indirection.IndirectList
, а затем вызываете ее метод isInstantiated()
. Следующая ссылка содержит дополнительную информацию:
http://www.eclipse.org/eclipselink/api/1.1/org/eclipse/persistence/indirection/IndirectList.html#isInstantiated.