Java 8 Spring Boot 2.0.5
I have following configuration which I am sure is correct. During debugging I can get values from collection of tools which is lazy loaded in UserInformations. I read that debugging is doing additional fetch to give user ability to get values from database, but simple System.out.print
in my endpoint should fail.
I want to lazy load the collection in @OneToMany
because now is loading eager and if I will have more data getting single UserInformation
will be to long. @OneToMany
is by default lazy but in my example is working as eager and I don't know why to repair it to fetch lazy.
This are my classes:
@Getter
@Setter
@NoArgsConstructor
public class ElectricTool {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@NotNull
@NotBlank
@NotEmpty
@Size(max = 64)
private String name;
@ManyToOne
private UserInformation userInformation;
public ElectricTool(String name) {
this.name = name;
}
}
@Getter
@Setter
@Entity
public class UserInformation {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@NotNull
@NotEmpty
@NotBlank
@Size(max = 32)
private String firstName;
@OneToMany(mappedBy = "userInformation")
private Set<ElectricTool> electricTools;
public UserInformation() {
this.electricTools = new HashSet<>();
}
public UserInformation(String firstName) {
this.firstName = firstName;
this.electricTools = new HashSet<>();
}
}
@Repository
public interface UserInformationRepository extends
JpaRepository<UserInformation, Long> {}
@Repository
public interface ElectricToolRepository extends
JpaRepository<ElectricTool, Long> {}
@RestController
@RequestMapping(value = "/lazy")
public class LazyController {
private UserInformationRepository userInformationRepository;
private ElectricToolRepository electricToolRepository;
public LazyController(UserInformationRepository userInformationRepository, ElectricToolRepository electricToolRepository) {
this.userInformationRepository = userInformationRepository;
this.electricToolRepository = electricToolRepository;
}
@GetMapping
public void checkLazy() {
userInformationRepository.findAll().get(0).getElectricTools().stream().findFirst().get();
}
}
Configuration
spring.datasource:
url: jdbc:postgresql://localhost:5432/lazy
username: postgres
password: admin
spring.jpa:
show-sql: true
hibernate.ddl-auto: create-drop
database-platform: org.hibernate.dialect.PostgreSQLDialect
properties.hibernate.jdbc.lob.non_contextual_creation: true
Result of System.out.print: This should be lazy loading exception
Result of debugging: While debugging i have access to electric tool but it should throw lazy loading exception
When I turn on showing of SQL and change method in controller to directly get electricTool from userInformation it return the object but should throw an exception and the sql look like this
select userinform0_.id as id1_1_, userinform0_.first_name as first_na2_1_ from user_information userinform0_
select electricto0_.user_information_id as user_inf3_0_0_, electricto0_.id as id1_0_0_, electricto0_.id as id1_0_1_, electricto0_.name as name2_0_1_, electricto0_.user_information_id as user_inf3_0_1_ from electric_tool electricto0_ where electricto0_.user_information_id=?
select userinform0_.id as id1_1_, userinform0_.first_name as first_na2_1_ from user_information userinform0_
When you asked me why i think i should get lazy fetch exception during asking about element in collection annotated by @OneToMany i just want to show you the same configuration as above but in second project which work correctly, but lets look at code
@Entity
@Getter
@Setter
public class UserInformation {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String firstName;
@OneToMany(mappedBy = "userInformation")
private Set<Address> addresses;
public UserInformation() {
this.addresses = new HashSet<>();
}
public UserInformation(String firstName) {
this.firstName = firstName;
this.addresses = new HashSet<>();
}
}
@Entity
@Getter
@Setter
@NoArgsConstructor
public class Address {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String city;
@ManyToOne
private UserInformation userInformation;
public Address(String city) {
this.city = city;
}
}
@Repository
public interface UserInformationRepository extends JpaRepository<UserInformation, Long> {
}
@Repository
public interface AddressRepository extends JpaRepository<Address, Long> {
}
Configuration
spring.datasource:
url: jdbc:postgresql://localhost:5432/specification
username: postgres
password: admin
spring.jpa:
show-sql: true
hibernate.ddl-auto: create-drop
database-platform: org.hibernate.dialect.PostgreSQLDialect
properties.hibernate.jdbc.lob.non_contextual_creation: true
And when i try to execute that piece of code:
userInformationRepository.findAll()
I get LazyInitializationException and that is behavior which i want to get in the first example. So where is the mistake in first example because of findAll method give me all nested relations in debugger
Additional when i do the same execution as in first example i get LazyInitializationException
userInformationRepository.findAll().get(0).getAddresses().stream().findFirst().get();
failed to lazily initialize a collection of role: com.specification.specification.entity.borrow.UserInformation.addresses, could not initialize proxy - no Session