JPA (Hibernate) - сессия / транзакция и отложенная загрузка - PullRequest
2 голосов
/ 14 октября 2010

У меня есть проект Java EE, а база данных MySQL управляется с помощью ORM.Я много работал с Hibernate, чтобы понять, что я делаю неправильно, и мне кажется, что я понимаю сессию / транзакцию, но я не знаю, как решить эту проблему в моем случае / архитектуре.

У меня есть проект иЧеловек, который находится в двунаправленном отношении n: m с таблицей соединений.Проект является владельцем карты.Теперь я хочу удалить человека, который подключен к проекту.

Итак, я подумал, я могу сделать это:

Person person = findPersonById(personId);
Set<Project> projects = person.getProjects();
Iterator<Project> iterator = projects.iterator();
while (iterator.hasNext()) {
    Project project = iterator.next();
    if (project.getPersons().contains(person)) {
        project.getPersons().remove(person);
        projectDao.updateProject(project);
    }
}
personDao.removePerson(personId);

Но я получаю сообщение об ошибке в этой строке:

Iterator<Project> iterator = projects.iterator();

Но, похоже, это связано с:

Person person = findPersonById(personId);

и:

public Person findPersonById(int personId) {
    SessionFactory sessionFactory = HibernateUtil.getSessionFactory();
    Session sess = sessionFactory.getCurrentSession();

    Transaction tx = sess.beginTransaction();
    try {
        Person person = (Person)sess.createQuery("from Person where id = "+personId).list().get(0);
        tx.commit();
        return person;
    }
    catch (IndexOutOfBoundsException ex) {
        return null;
    }
}

Здесь я совершаю транзакцию и получаю только объект person, но не соответствующийпроекты.И итератор попытается их получить, но не сможет, потому что моя транзакция / сессия закрыта.Это из-за моей архитектуры:

У меня есть: IPersonService -> IPersonImplementation -> IPersonDao -> IPersonDaoImplementation , и только метод в IPersonDaoImplementation открывает и закрывает транзакцию.Поэтому в моей ServicePersonImplementation я не могу сделать несколько вещей, связанных с БД (я не хочу иметь FetchType.EAGER в моей аннотации @ManyToMany, потому что это приведет к загрузке большого количества ненужных вещей).Потому что, как только он возвращается из моей DaoImplementation, я не могу выполнять другие действия с возвращенным человеком (в моем случае получить все проекты, которые объединены с этим человеком).

Так что я могу сделать в моем случае?

С наилучшими пожеланиями Тим.

Обновление: PersonDaoImpl, метод удаления:

public void removePerson(int personId){
    Person p = findPersonById(personId);

    SessionFactory sessionFactory = HibernateUtil.getSessionFactory();
    Session sess = sessionFactory.getCurrentSession();

    Transaction tx = sess.beginTransaction();
    sess.delete(p);
    sess.flush();
    tx.commit();
}

Трассировка ошибки:

ОШИБКА: org.hibernate.LazyInitializationException - не удалось лениво инициализировать коллекцию роли: com.testdomain.testproject.domain.Person.projects, ни один сеанс или сеанс не был закрыт org.hibernate.LazyInitializationException: не удалось лениво инициализировать коллекциюrole: com.testdomain.testproject.domain.Person.projects, ни один сеанс или сеанс не были закрыты в org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationException (AbstractPersistentCollection.java:383) в org.hibernate.collection.AbstractPersistentControlTollectionTollectionTollectionTollection.ollectionTollection.ollectionTollection.ollectionTollection.ollectionJava: 375) в org.hibernate.collection.AbstractPersistentCollection.initialize (AbstractPersistentCollection.java:368) в org.hibernate.collection.AbstractPersistentCollection.read (AbstractPersistentCollection.java:111) в org.hibernate.collection.PersistentSetlection.PolistentSetlection.186) в com.testdomain.testproject.dao.impl.PersonDaoImplHibernate.removePerson (PersonDaoImplHibernate.java:71) в com.testdomain.testproject.service.impl.PersonServiceImpl.removePerson (PersonServiceImpl.jtestpromain.test для com.test)..service.PersonTest.testRemovePerson (PersonTest.java:180) в sun.reflect.NativeMethodAccessorImpl.invoke0 (собственный метод) в sun.reflect.NativeMethodAccessorImpl.invoke (NativeMethodAccessorImpl.jd.java: 25) в java.lang.reflect.Method.invoke (Method.java:597) в org.junit.runners.model.FrameworkMethod $ 1.runReflectiveCall (FrameworkMethod.java:44) в org.junit.internal.runners.model.ReflectiveCallable.run (ReflectiveCallable.java:15) в org.junit.runners.model.FrameworkMethod.invokeExplosively (FrameworkMethod.java:41) в org.junit.internal.runners.statements.InvokeMethod.eavaate) ()по адресу org.junit.runners.BlockJUnit4ClassRunner.runNotIgnored (BlockJUnit4ClassRunner.java:79) по адресу org.junit.runners.BlockJUnit4ClassRunner.runChild (BlockJUnit4ClassRunner.javaitunjun) в org.junit.runners.ParentRunner $ 3.run (ParentRunner.java:193) в org.junit.runners.ParentRunner $ 1.schedule (ParentRunner.java:52)в org.junit.runners.ParentRunner.runChildren (ParentRunner.java:191) в org.junit.runners.ParentRunner.access $ 000 (ParentRunner.java:42) в org.junit.runners.ParentRunner $ 2.evaluate (ParentRunner.java:184) в org.junit.internal.runners.statements.RunBefores.evaluate (RunBefores.java:28) в org.junit.runners.ParentRunner.run (ParentRunner.java:236) в org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run (JUnit4TestReference.java:46) в org.eclipse.jdt.internal.junit.runner.TestExecution.run (TestExecution.java:38) в org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests (RemoteTestRunner.java:467) в org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests (RemoteTestRunner.java:683) в org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run (RemoteTestRunner.java:390) в org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main (RemoteTestRunner.java:197) Не удалось удалить Person: не удалось лениво инициализировать коллекцию ролей: com.testdomain.testproject.domain.Person.projects, ни один сеанс или сеанс не был закрыт

Ответы [ 2 ]

6 голосов
/ 14 октября 2010

Что вы действительно хотите сделать, так это вставить весь код удаления Person в метод remove () PersonDao.Внутри этого метода вы хотите сделать следующее:

  • начать транзакцию
  • Найти экземпляр Person по идентификатору
  • Получить его проектный набор и удалить его из всехих
  • Удалите сам экземпляр Person
  • совершить транзакцию

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

Таким образом, ваш код может выглядеть примерно так:

public void removePerson(int personId) {
  SessionFactory sessionFactory = HibernateUtil.getSessionFactory();
  Session sess = sessionFactory.getCurrentSession();
  Transaction tx = sess.beginTransaction();

  try {
    Person person = (Person)sess.createQuery("from Person where id = "+personId).list().get(0);
    Set<Project> projects = person.getProjects();
    for (Project project : projects) {
      if (project.getPersons().contains(person)) {
        project.getPersons().remove(person);
        sess.saveOrUpdate(project);
      }
    }

    sess.delete(person);
    tx.commit();
  }  catch (Exception e) {
     System.err.println("Failed deleting Person: "+e.getMessage());
  }
}

(Примечание: это примерно ближе к псевдокоду и не тестировалось в реальной IDE)

1 голос
/ 14 октября 2010

У вас есть два варианта на самом деле. Первый - выполнить это в вашей службе / реализации DAO.

projectDao.removePersonFrom(Person personToRemove, Project projectToRemoveFrom);

personDao.removeProjectFrom(Project projectToRemove, Person personToRemoveFrom);

У меня обычно есть класс Model, связанный с представлением, и иногда я делаю определенные методы в них транзакционными (я использую Spring) для такого рода вещей.

- изменить -

Внутри даосов вы создаете сеанс / транзакцию, а затем можете выполнить код, который не удался. Код, который вы разместили, должен нормально работать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...