Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ElementCollection and "failed to lazily initialize a collection of role" exception

I'm very new to Spring and I'm trying to figure out how to use @ElementCollection.

I have the following classes:

@Embeddable
public class Phone {
      private String type;
      private String areaCode;
      @Column(name="P_NUMBER")
      private String number;

    public Phone() {
    }

    public Phone(String type, String areaCode, String number) {
        super();
        this.type = type;
        this.areaCode = areaCode;
        this.number = number;
    }

    public String getNumber() {
        return number;
    }

    public void setNumber(String number) {
        this.number = number;
    }


    public String getAreaCode() {
        return areaCode;
    }

    public void setAreaCode(String areaCode) {
        this.areaCode = areaCode;
    }

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }
}

@Entity
public class Employee {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "EMP_ID")
    private long id;

    @ElementCollection//(fetch=FetchType.EAGER)
    @CollectionTable(name = "PHONE", joinColumns = @JoinColumn(name = "OWNER_ID"))
    private List<Phone> phones  = new ArrayList<Phone>();;

    public Employee() {
    }

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public List<Phone> getPhones() {
        return phones;
    }

    public void setPhones(List<Phone> phones) {
        this.phones = phones;
    }
}

Repository:

@Repository
public interface EmployeeRepository extends CrudRepository<Employee, Long>{

    public Employee findById(long id);

}

Then I use it in main method:

public static void main(String[] args) {
        ConfigurableApplicationContext context = SpringApplication.run(Application.class, args);
        EmployeeRepository repository = context.getBean(EmployeeRepository.class);

        Phone phone = new Phone("work", "613", "494-1234");
        Employee emp = new Employee();
        emp.getPhones().add(phone);
        repository.save(emp);

        emp = repository.findById(1);
        for (Phone p : emp.getPhones()) {
            System.out.println(p.getNumber());
        }

        context.close();

    }

It throws exception (when emp.getPhones() is called): Exception in thread "main" org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: elcol.repository.Employee.phones, could not initialize proxy - no Session

If I add (fetch=FetchType.EAGER) to @ElementCollection annotation(commented in the code above in Employee class) - everything is ok.

How can I fix this without FetchType.EAGER?

like image 749
LSO Avatar asked Oct 30 '14 09:10

LSO


People also ask

How do I fix lazy initialization exception?

The right way to fix a LazyInitializationException is to fetch all required associations within your service layer. The best option for that is to load the entity with all required associations in one query.

How do you load a lazy object in hibernate?

To enable lazy loading explicitly you must use “fetch = FetchType. LAZY” on an association that you want to lazy load when you are using hibernate annotations. @OneToMany( mappedBy = "category", fetch = FetchType.


1 Answers

In findById(long id) implementation, add this Hibernate.initialize(emp.getPhones()).

Your repository service should return all the data you will need already initialized so the client that calls the service stays independent of it. In short, If you don't need employees phones on the client side, don't initialize it. If you do need it - initialize it.

EDIT

With spring data you obviously don't have the implementation, so you can specify the query which will be used, and fetch the data in the query (the question is tagged with jpa so I guess you can use JpaRepository)

@Repository
public interface EmployeeRepository extends JpaRepository<Employee, Long>{

    @Query("SELECT e FROM Employee e JOIN FETCH e.phones WHERE e.id = (:id)")
    public Employee findById(long id);
}
like image 99
Predrag Maric Avatar answered Sep 23 '22 12:09

Predrag Maric