2015-05-29 3 views
1

У меня есть три сущности Employee, Person и EmailAdress, как указано ниже:LazyInitializationException при обновлении Entity в базе данных

@Entity 
public class Employee { 
    private Person person; 

    //Other data members 

    @ManyToOne(fetch=FetchType.LAZY, cascade = CascadeType.MERGE) 
    @JoinColumn(name="person_id") 
    public Partner getPerson() { 
     return person; 
    } 

    //Other getter and setters 
} 

@Entity 
public class Person { 
    private Set<EmailAddress> emails; 

    //Other data members 

    @OneToMany(fetch=FetchType.LAZY, mappedBy="person", cascade=CascadeType.ALL) 
    public Set<EmailAddress> getEmails() { 
     return emails; 
    } 

    public void setEmails(Set<EmailAddress> emails) { 
     this.emails = emails; 
     for(EmailAddress email : this.emails) { 
      email.setPerson(this); 
     } 
    } 

    //Other getter and setters 
} 

@Entity 
public class EmailAddress { 
    private Person person; 
    private String email; 
    private String emailType; 

    //getter and setter 

    @ManyToOne(fetch=FetchType.EAGER) 
    @JoinColumn(name="partner_id") 
    public Partner getPerson() { 
     return person; 
    } 
} 

И EmployeeDAO, который выполняет сохранение, обновление, удаление операции на сущности Employee.

@Repository("employeeDAO") 
@Transactional 
public class EmployeeDAO { 

    public Employee saveOrUpdate(Employee emp) { 
     try { 
      return (Employee) sessionFactory.getCurrentSession().merge(emp); 
     } catch(Exception excp) { 
      //Handle exception 
     } 

     return null; 
    } 

    //Other methods 
} 

Это saveOrUpdate() в EmployeeDAO сохранить Employee объект в БД без каких-либо проблем, но когда я использую тот же saveOrUpdate() для обновления Работника, он терпит неудачу с LazyInitializationException. Ниже приводится EmployeeDAOTest:

//Test class 
public class EmployeeDAOTest extends AbstractTestNGSpringContextTests { 

    @Autowired 
    private EmployeeDAO employeeDAO; 

    private Employee createDummyEmployee() { 
     // Create dummy employee initialized with Person and EmailAddress 

     return employee; 
    } 

    @Test 
    public void testSaveOrUpdate() { 
     Employee emp = createDummyEmployee(); 

     //Test Save/Insert 
     Employee savedEmp = employeeDAO.saveOrUpdate(emp); 
     Assert.assertNotNull(savedEmp);  //Works fine. Employee gets saved correctly 

     //Test Update 
     savedEmp.getPerson().setName("Updated Name"); 
     Employee updatedEmp = employeeDAO.saveOrUpdate(savedEmp); 
     Assert.assertNotNull(updatedEmp); // Fails... because of "org.hibernate.LazyInitializationException: could not initialize proxy - no Session" 
    } 
} 

Я сделал немного поискового запроса, прежде чем размещать этот вопрос здесь. И выяснили, что есть два способа это исправить:

  1. Не используйте отложенной инициализации ленивым = т.е. ложь. Но этот подход имеет свои собственные последствия. И не может использовать этот подход из-за его проблемы с производительностью .

  2. Использовать @PersistenceContext (type = PersistenceContextType.EXTENDED). Это решает проблему, но я думаю, что при таком подходе Spring не управляет EntityManager/TransactionManager, и мне нужно управлять этими мной. Есть ли способ, которым управляет весна? EntityManager/TransactionManager с таким подходом, чтобы я не должен сам управлять этим.

Или есть ли лучший подход для решения этой проблемы?

ответ

0

Внутри вашего метода испытаний созданы две отдельные сессии, и при попытке сделать обновление getPerson терпит неудачу из-за lazyInitializatin ....

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

import rg.springframework.transaction.annotation.Transactional 
... 
    @Test 
    @Transactional 
    public void testSaveOrUpdate() { 

Точно так же, в реальной бизнес-кода, всякий раз, когда вы получаете доступ к DAO несколько раз внутри метода, этот метод должен быть аннотирования, как транзакционный поддерживать контекст. Конечно, побочный эффект заключается в том, что вся логика метода будет терпеть неудачу, если одна из операций DAO завершится неудачно, но это, вероятно, демонтированный bahaviour.

+0

Спасибо @Zielu .. он работал, чтобы исправить исключение LazyInitializationException. Но я получаю ** org.hibernate.PropertyAccessException: Исключение произошло внутри setter Person.emails ** .. пожалуйста, проверьте обновленную реализацию setEmails() – Saumesh

+0

Задайте новый вопрос о новой проблеме и включите в нее всю трассировку стека. – Zielu

Смежные вопросы