В Hibernate мы имеем два класса со следующими классами с JPA отображения:Ленивая загрузка собственности и session.get проблема
package com.example.hibernate
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
@Entity
public class Foo {
private long id;
private Bar bar;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
@ManyToOne(fetch = FetchType.LAZY)
public Bar getBar() {
return bar;
}
public void setBar(Bar bar) {
this.bar = bar;
}
}
package com.example.hibernate
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
public class Bar {
private long id;
private String title;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
}
Теперь, когда мы загружаем из базы данных объекта из класса Foo с помощью сеанса получить, например:
Foo foo = (Foo) session.get (Foo.class, 1/* или какой-либо другой идентификатор, который существует в БД * /); Член панели foo - это прокси-объект (в нашем случае прокси-сервер javassist, но он может быть cglib одним в зависимости от используемого вами оператора байт-кода), который не инициализируется. Если вы затем используете session.get для извлечения объекта Bar, который является членом только что загруженного класса Foo (мы находимся в том же сеансе), Hibernate не выдает другой запрос БД и не извлекает объект из сеанса (первый уровень) кэш. Проблема в том, что это прокси для класса Bar, который не инициализирован и пытается вызвать этот объект. GetId() вернет 0, а getTitle() вернет значение null. Наше текущее решение является довольно некрасиво и проверяет, является ли объект, возвращаемый из ГЭТ является прокси вот код (образуют общую реализацию DAO):
@SuppressWarnings("unchecked")
@Override
@Transactional(readOnly = true)
public <T extends IEntity> T get(Class<T> clazz, Serializable primaryKey) throws DataAccessException {
T entity = (T) currentSession().get(clazz, primaryKey);
if (entity != null) {
if (LOG.isWarnEnabled()) {
LOG.warn("Object not found for class " + clazz.getName() + " with primary key " + primaryKey);
}
} else if (entity instanceof HibernateProxy){ // TODO: force initialization due to Hibernate bug
HibernateProxy proxy = (HibernateProxy)entity;
if (!Hibernate.isInitialized(proxy)) {
Hibernate.initialize(proxy);
}
entity = (T)proxy.getHibernateLazyInitializer().getImplementation();
}
return entity;
}
Есть ли лучший способ сделать это, не могли найти решение на форуме Hibernate и не нашло проблемы в JIRA Hibernate.
Примечание: мы не можем просто использовать foo.getBar() (который будет инициализировать прокси-сервер должным образом), чтобы получить объект класса Bar, поскольку операция session.get для извлечения объекта Bar не знает (или не заботится об этом), что класс Bar также является ленивым членом объекта Foo, который был только что извлечен.
Загрузка в другой сеанс не является вариантом: реальная проблема более сложна, но короткий ответ заключается в том, что мы не можем. – talg 2008-09-15 06:43:46