1

I have three entities Employee, Person and EmailAdress as given below:

@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;
    }
}

And EmployeeDAO that performs save, updates, delete operation on Employee entity.

@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
}

This saveOrUpdate() in EmployeeDAO save Employee entity to DB without any problem, but when I use same saveOrUpdate() to update Employee, it fails with LazyInitializationException. Following is the 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"
    }
}

I did little bit of googling before posting this question here. And figured out that there are two ways to fix it:

  1. Don't use LAZY initialization i.e lazy=false. But this approach has its own implication. And can't use this approach because of its performance issue.

  2. Use @PersistenceContext(type = PersistenceContextType.EXTENDED). This solves the problem, but I think, with this approach Spring does not manage EntityManager/TransactionManager and I have to manage these myself. Is there any way that spring manage EntityManager/TransactionManager with this approach so that I don't have to manage it myself.

Or is there any better approach to fix this problem?

Saumesh
  • 71
  • 1
  • 2
  • 5

1 Answers1

0

Inside your test method two separate sessions are created, and when attempting to do the update getPerson fails due to the lazyInitializatin....

You should annotate your method with @Transactional which would maintain same persistent context over the whole test method.

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

Similarly, in your real business code, whenever you access the DAO multiple times inside the method, this method should be annotate as Transactional to maintain the context. Of course the side effect is, that the whole method logic will fail if one of the DAO operations fails but that is probably the demannded bahaviour.

Zielu
  • 8,312
  • 4
  • 28
  • 41
  • Thanks @Zielu.. it worked to fix LazyInitializationException. But I am getting **org.hibernate.PropertyAccessException: Exception occurred inside setter of Person.emails** .. please check updated implementation of setEmails() – Saumesh May 30 '15 at 18:05
  • Post a new question about the new problem and include the whole stack trace in it. – Zielu May 31 '15 at 10:29