2010-10-14 2 views
2

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

У меня есть проект и лицо, которые находятся в двунаправленном соотношении 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 я не могу выполнять некоторые связанные с DB вещи (я не хочу иметь FetchType.EAGER в моей аннотации @ManyToMany, потому что это загрузится в ненужные вещи). Поскольку, как только он возвращается из моей DaoImplementation, я не могу выполнять другие действия с возвращенным человеком (в моем случае получить все проекты, которые объединены с этим человеком).

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

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

Update: 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 - не удалось инициализировать лениво коллекцию роли: ком .testdomain.testproject.domain.Person.projects, сеанс или сеанс закрыты. org.hibernate.LazyInitializationException: не удалось лениво инициализировать коллекцию роли: com.testdomain.testproj ect.domain.Person.projects, ни одна сессия или сеанс был закрыт на org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationException (AbstractPersistentCollection.java:383) в org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationExceptionIfNotConnected (AbstractPersistentCollection.java:375) на org.hibernate.collection.AbstractPersistentCollection.initialize (AbstractPersistentCollection.java:368) в org.hibernate.collection.AbstractPersistentCollection.read (AbstractPersistentCollection.java:111) в org.hibernate.collection.PersistentSet.iterator (PersistentSet. java: 186) at com.testdomain.testproject.dao.impl.PersonDaoImplHibernate.removePerson (PersonDaoImplHibernate.java:71) at com.testdomain.testproject.service.impl.PersonServiceImpl.removePerson (PersonServiceImpl.java:88) at com.testdomain.testproject.service.PersonTest.testRemovePerson (PersonTest.java:180) на sun.reflect.NativeMethodAccessorImpl.invoke0 (нативный метод) на sun.reflect.NativeMethodAccessorImpl.invoke (NativeMethodAccessorImpl.java:39) в sun.reflect.DelegatingMethodAccessorImpl.invoke (DelegatingMethodAccessorImpl.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) at org.jun it.runners.model.FrameworkMethod.invokeExplosively (FrameworkMethod.java:41) at org.junit.internal.runners.statements.InvokeMethod.evaluate (InvokeMethod.java:20) at org.junit.runners.BlockJUnit4ClassRunner.runNotIgnored (BlockJUnit4ClassRunner.java:79) на org.junit.runners.BlockJUnit4ClassRunner.runChild (BlockJUnit4ClassRunner.java:71) на org.junit.runners.BlockJUnit4ClassRunner.runChild (BlockJUnit4ClassRunner.java:49) в org.junit.runners. ParentRunner $ 3.run (ParentRunner.java:193) at org.junit.runners.ParentRunner $ 1.schedule (ParentRunner.java:52) at org.junit.runners.ParentRunner.runChildren (ParentRunner.java:191) at org.junit.runners.ParentRunner.access $ 000 (ParentRunner.java:42) на org.junit.run ners.ParentRunner $ 2.оценить (ParentRunner.java:184) на org.junit.internal.runners.statements.RunBefores.evaluate (RunBefores.java:28) на org.junit.runners.ParentRunner.run (ParentRunner.java : 236) at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run (JUnit4TestReference.java:46) at 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) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main (RemoteTestRunner.java:197)) Не удалось удалить пользователя: не удалось лениво инициализировать коллекцию роли: com.testdomain.testproject.domain.Person.projects, сеанс или сеанс закрыты

+0

Какая ошибка? – willcodejavaforfood

+0

Ленивая инициализация или если я делаю некоторые изменения, я получаю ошибку, что ее нельзя удалить из-за ограничений внешнего ключа, но теперь я понимаю, почему проблема возникает, но как я могу решить эту элегантность? Если итерация будет внутри транзакции, у меня не будет этой проблемы ?! – Tim

+0

Правильно, вы хотите удалить Личность из любых проектов внутри метода удаления PersonDao – Ophidian

ответ

6

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

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

в JPA, вам не нужно делать ничего больше, чем это, но я верю в прямом Hibernate йо u может потребоваться 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)

+0

Я добавил _person.getProjects(); _ перед _tx.commit(); _ но, к сожалению, тот же результат. – Tim

+0

Плохо, я должен был внимательно прочитать вопрос. Я обновил свой ответ. – Ophidian

+0

Я использовал ваш код, но я получаю ту же ошибку в этой строке: for (Project project: projects) {- ленивое исключение инициализации – Tim

1

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

projectDao.removePersonFrom(Person personToRemove, Project projectToRemoveFrom); 

personDao.removeProjectFrom(Project projectToRemove, Person personToRemoveFrom); 

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

--edit--

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

+0

И каков должен быть элемент метода удаленияПерсона? Потому что есть один человек и только один проект. Но я не знаю проекты, с которыми связан человек. Я также использовал Spring для Injection Dependency. – Tim

+0

Я имел в виду, что я использую его для объявления границ транзакций. – willcodejavaforfood

+0

. Вы также правы, я должен поместить все вещи из ServiceImpl в DaoImpl внутри транзакции. – Tim