In Student class, I am passing the id manually and all my entity-relationship are in LAZY mode.
But because I am passing the id, Spring DATA JPA (Hibernate) will treat as a merge request and make a SELECT call and will try to merge it. But I can not understand why it is trying to JOIN all relationships.
I was expecting select call for student table and not joining other tables. I can not understand why it is happening ?
select
student0_.uuid as uuid1_2_3_,
student0_.address_uuid as address_3_2_3_,
student0_.name as name2_2_3_,
address1_.uuid as uuid1_0_0_,
address1_.city_uuid as city_uui5_0_0_,
address1_.lat as lat2_0_0_,
address1_.lon as lon3_0_0_,
address1_.pincode as pincode4_0_0_,
city2_.uuid as uuid1_1_1_,
city2_.name as name2_1_1_,
subjects3_.student_uuid as student_4_3_5_,
subjects3_.uuid as uuid1_3_5_,
subjects3_.uuid as uuid1_3_2_,
subjects3_.course_start_date as course_s2_3_2_,
subjects3_.name as name3_3_2_,
subjects3_.student_uuid as student_4_3_2_
from
student student0_
inner join
address address1_
on student0_.address_uuid=address1_.uuid
left outer join
city city2_
on address1_.city_uuid=city2_.uuid
left outer join
subject subjects3_
on student0_.uuid=subjects3_.student_uuid
where
student0_.uuid=?
@Entity
public class Student {
@Id
private UUID uuid;
@Column(nullable = false)
private String name;
@OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL, optional = false)
private Address address;
@OneToMany(mappedBy = "student", orphanRemoval = true, cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private List<Subject> subjects;
}
@Entity
public class Subject {
@Id
@GeneratedValue
private UUID uuid;
@Column(nullable = false)
private String name;
@Column(nullable = false)
private ZonedDateTime courseStartDate;
@ManyToOne(fetch = FetchType.EAGER)
private Student student;
}
@Entity
public class City {
@Id
@GeneratedValue
private UUID uuid;
@Column(nullable = false)
private String name;
}
@Entity
public class Address {
@Id
@GeneratedValue
private UUID uuid;
@OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
private City city;
@Column(nullable = false)
private String pincode;
@Column
private double lat;
@Column
private double lon;
}
Test Case :
@ExtendWith(SpringExtension.class)
@DataJpaTest
@AutoConfigureTestDatabase(replace = NONE)
public class StudentRepositoryIT {
@PersistenceContext
private EntityManager entityManager;
@Rollback(value = false)
@Test
public void should_fetch_student() {
// GIVEN
UUID uuid = UUID.randomUUID();
Student john = new Student().setName("John Wick").setUuid(uuid);
City newyork = new City().setName("Newyork City");
Address address = new Address().setCity(newyork)
.setLat(12.3)
.setLon(13.4)
.setPincode("010101");
john.setAddress(address);
Subject maths = new Subject().setName("maths").setCourseStartDate(ZonedDateTime.now()).setStudent(john);
Subject english = new Subject().setName("english").setCourseStartDate(ZonedDateTime.now()).setStudent(john);
Subject hindi = new Subject().setName("hindi").setCourseStartDate(ZonedDateTime.now()).setStudent(john);
Subject geology = new Subject().setName("geology").setCourseStartDate(ZonedDateTime.now()).setStudent(john);
Subject physics = new Subject().setName("physics").setCourseStartDate(ZonedDateTime.now()).setStudent(john);
Subject science = new Subject().setName("science").setCourseStartDate(ZonedDateTime.now()).setStudent(john);
john.setSubjects(List.of(maths, english, hindi, geology, physics, science));
studentRepository.saveAndFlush(john);
TestTransaction.end();
// WHEN
TestTransaction.start();
Student student = entityManager.find(Student.class, uuid);
System.out.println(student);
System.out.println(student.getAddress());
Address address1 = student.getAddress();
System.out.println(address1.getLat());
// THEN
check query console
}
}
CodePudding user response:
It does so because you are using CascadeType.ALL
which means that Hibernate should cascade also for the merge
operation. In order to cascade, Hibernate must load the data first and instead of loading the data by doing individual selects, Hibernate uses joins.
CodePudding user response:
I'm not sure about City
, but for the others Hibernate needs the join to determine if the respective field is null
or not, which it needs to know before returning your root entity.