i am having an error with the fetch type and i dont know how to fix it! Please help me if u can. :D. Using java 8
THE COMMAND LINE RUNNER:
@Autowired CustomTableRepository tr;
@Autowired UserRepository ur;
@Autowired RoleRepository rr;
@Bean
CommandLineRunner commandLineRunner() {
return args -> {
tr.save(new CustomTable(null, true, null));
tr.save(new CustomTable(null, true, null));
tr.save(new CustomTable(null, true, null));
tr.save(new CustomTable(null, true, null));
tr.save(new CustomTable(null, true, null));
ur.save(new User(null, "cpthermes", "thanatos", 123987456l, 3123231l, null,null));
ur.save(new User(null, "moni1008", "milky", 123987456l, 31232131l, null, null));
ur.save(new User(null, "mario", "zoro123", 1231231l, 32123l, null, null));
};
}
THE MODEL CLASSES:
@Entity
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Reservation {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long id;
private Boolean accepted;
@ManyToOne
@JoinColumn(name = "user_id")
private User user;
@OneToOne
@JoinColumn(name = "table_id")
private CustomTable table;
private LocalTime time;
}
@Entity
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long id;
private String username;
private String password;
private Long number;
private Long balance;
@OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true)
private List<Reservation> reservations;
@ManyToMany
private Collection<Role> roles;
}
@Entity
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Role {
@Id
@GeneratedValue
private Long id;
private String type;
}
THE ERROR:
Could not write JSON: failed to lazily initialize a collection of role: com.mile.pc.mile.restoraunt.app.model.User.reservations, could not initialize proxy - no Session; nested exception is com.fasterxml.jackson.databind.JsonMappingException: failed to lazily initialize a collection of role: com.mile.pc.mile.restoraunt.app.model.User.reservations, could not initialize proxy - no Session (through reference chain: java.util.ArrayList[0]->com.mile.pc.mile.restoraunt.app.model.User["reservations"])
org.springframework.http.converter.HttpMessageNotWritableException: Could not write JSON: failed to lazily initialize a collection of role: com.mile.pc.mile.restoraunt.app.model.User.reservations, could not initialize proxy - no Session; nested exception is com.fasterxml.jackson.databind.JsonMappingException: failed to lazily initialize a collection of role: com.mile.pc.mile.restoraunt.app.model.User.reservations, could not initialize proxy - no Session (through reference chain: java.util.ArrayList[0]->com.mile.pc.mile.restoraunt.app.model.User["reservations"])
.................... .................... .................... .................... .................... .................... Ty for reading.
CodePudding user response:
The issue is that at the time Spring tries to convert your entities to JSON, Hibernate has no way of retrieving the lazy-loaded reservations
from the database. You have a couple of possibilities to fix this:
- Using FetchType.EAGER strategy
@Entity
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long id;
private String username;
private String password;
private Long number;
private Long balance;
@OneToMany(fetch = FetchType.EAGER, mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true)
private List<Reservation> reservations;
@ManyToMany
private Collection<Role> roles;
}
- Using Join fetching in your custom Repository method:
@Query(value = "SELECT u FROM User u JOIN FETCH u.reservations")
List<User> findAllUsers();
You can read more about this issue at the following online resource: https://www.baeldung.com/hibernate-initialize-proxy-exception
CodePudding user response:
For @OneToMany
and @ManyToMany
hibernate by default uses lazy fetch approach. i.e. It simply does not load your child entities when you ask it get the parent entity. So you can have two simpler ways to overcome this problem.
- Use
fetch=FetchType.EAGER
onReservations
.
Simply update below in Role class.
@OneToMany(fetch = FetchType.EAGER, mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true)
private List<Reservation> reservations;
But be aware about the performance issue. Hibernate is going to load the Reservation
entities all the time when you ask for a Role
entity. If that is not a concern for your application, you can easily go for this.
- Use
JOIN FETCH
approach
Define a @Query
method using join fetch
and use that instead of predefined
find()
method. In that way you can ask hibernate what other tables to load
whenever you are asking to load the parent entity.
@Query(value = "SELECT u FROM User u JOIN FETCH u.reservations")
List<User> findUsersWithReservations();
Below article has further details around it along with some other approaches.