Home > Enterprise >  Why is Hibernate making a select call with join when manually passing id?
Why is Hibernate making a select call with join when manually passing id?

Time:08-10

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
    }
}

Entity Relationship diagram enter image description here

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.

  • Related