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?
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.
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.
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);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With