Вопрос

У меня проблема с гибернатом и ленициализированным течением. Я искал и нашел много ответов, но я не могу использовать их, чтобы решить мою проблему, потому что я должен сказать, я новичок в спячью.

Я запускаю Junit Tests, в случае ошибки этой:

@Test
public void testAddPerson() {
    Set<Person> persons = service.getAllPersons();

    // create new person
    Person person = new Person();
    person.setEmail("john@doe.com");
    Project testProject = serviceProj.findProjectById(1);

    HashSet<Project> lister = new HashSet<Project>();
    lister.add(testProject);
    person.setProjects(lister);
    service.addPerson(person);

    testProject.getPersons().add(person);
    ...
}

Последняя показанная строка:

testProject.getPersons().add(person);

бросает эту ошибку:

org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.doe.john.domain.Project.persons, no session or session was closed

Человек и проект являются двунаправленными N: M:

Человек.java:

@ManyToMany(mappedBy="persons")
private Set<Project> projects = new HashSet<Project>();

Project.java:

@ManyToMany
@JoinTable(name = "Project_Person",
    joinColumns = {@JoinColumn(name="project_id", referencedColumnName="id")},
    inverseJoinColumns = {@JoinColumn(name="person_id", referencedColumnName="id")}
)
private Set<Person> persons = new HashSet<Person>();

Так в чем проблема?

Это было полезно?

Решение

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

Легкий выход - это изменить его на fethtype.eager, который гарантирует, что коллекция населяется прямо.

--Обновить--

У меня недавно была очень такая же проблема, и я оказался модифицировать мою реальную услугу, чтобы иметь дело с такими вещами. Объявите метод AddPerson в вашем классе проектов.

public void addPersonTo(Project project, Person person)
{
  project = em.merge(project); //EntityManager, not sure what you are using but you get the idea hopefully
  project.addPerson(person);
}

Другие советы

Поместите свой код в транзакцию - это решит проблему для вас

Ты можешь попробовать

person.getProjects().Add(testProject)

вместо

HashSet<Project> lister = new HashSet<Project>();
lister.add(testProject);
person.setProjects(lister);

Вы должны делать это, так как иначе вы будете выдумать с гибернацией управляемой коллекции.

От справки с гибернацией:

По умолчанию Hibernate3 использует ленивую выборную форму для коллекций и ленивых прокси-приевок для однозначных ассоциаций. Эти по умолчанию имеют смысл для большинства ассоциаций в большинстве заявок.

Если вы устанавливаете Hibernate.default_batch_fetch_size, Hibernate будет использовать оптимизацию пакетной выборки для ленивой выборки. Эта оптимизация также может быть включена на более гранулированном уровне.

Помните, что доступ к ленивому ассоциации за пределами контекста открытой сессии Hibernate приведет к исключению. Например:

s = sessions.openSession();
Transaction tx = s.beginTransaction();

User u = (User) s.createQuery("from User u where u.name=:userName")
.setString("userName", userName).uniqueResult();
Map permissions = u.getPermissions();

tx.commit();
s.close();

Integer accessLevel = (Integer) permissions.get("accounts");  // Error!

Поскольку коллекция разрешений не была инициализирована, когда сеанс был закрыт, коллекция не сможет загрузить его состояние. Hibernate не поддерживает ленивую инициализацию для отдельных объектов. Это может быть закреплено путем перемещения кода, который читает из коллекции, прежде чем транзакция будет совершена.

Кроме того, вы можете использовать не ленивую коллекцию или ассоциацию, указав Lazy = «False» для сопоставления ассоциации. Однако предполагается, что ленивая инициализация используется практически для всех коллекций и ассоциаций. Если вы определяете слишком много не ленивых ассоциаций в вашей объектной модели, Hibernate будет получать всю базу данных в память в каждой транзакции.

С другой стороны, вы можете использовать присоединение к выходу, который не ленивый по своей природе, вместо того, чтобы выбрать получение в конкретной транзакции. Теперь мы объясним, как настроить стратегию получения. В Hibernate3 механизмы выбора стратегии извлечения идентичны однозначным ассоциациям и коллекциям.

Таким образом, вы должны закрыть сеанс после доступа к коллекции!

Вместо :

service.addPerson(person);

testProject.getPersons().add(person);

Я думаю, что у вас должен быть:

testProject.getPersons().add(person);
service.addPerson(person);
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top