JPQL left Соединения и Criteria API объединяет (левый и внутренний), создавая дополнительные запросы БД для инициализации ассоциаций - PullRequest
0 голосов
/ 28 января 2019

У меня ниже двух сущностей. Сущность Instructor имеет отношение oneToMany к сущности Vehicle.

public class Instructor {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO, generator = "native")
    @GenericGenerator(name = "native", strategy = "native")
    private int id;
    @Version
    @Column(columnDefinition = "int(11) not null default 0")
    private int version = 0;
    @OneToMany(mappedBy = "instructor", orphanRemoval = true, cascade = CascadeType.ALL)
    private Set<Vehicle> vehicles = new HashSet<>();  

.....

 public class Vehicle {
        @Id
        @GeneratedValue(strategy = GenerationType.AUTO, generator = 
 "native")
        @GenericGenerator(name = "native", strategy = "native")
        private int id;
        @ManyToOne(fetch = FetchType.LAZY)
        private Student student;
        @ManyToOne(fetch = FetchType.LAZY)
        private Instructor instructor;

Я хочу получить всех инструкторов вместе с их транспортными средствами в одном запросе.Ниже я попробовал четыре способа сделать это, но я не могу сделать это с тестовым примером 2, 3 и 4.

Тестовый пример 1: с предложением JPQL join fetch.

            @Test
            @Transactional
            @Rollback(false)
            public void fetchTest1(){   
                    List<Instructor> instructorsJpqlJoinFetch = em
                        .createQuery("select distinct i from 
        Instructor i join fetch i.vehicles v ", 
        Instructor.class)
                        .getResultList();
                print(instructorsJpqlJoinFetch);

            }

    private void print(List<Instructor> instructors) {
    instructors.forEach(i -> {
    System.out.println("######Instructor Name : " + i.getName());
    i.getVehicles().forEach(v -> {
            System.out.println("######Instructor Vehicle 
                   Number : " + v.getVehicleNumber());
                });

        });

Db Запрос отправлен в БД для случая 1:

select
        distinct instructor0_.id as id1_2_0_,
        vehicles1_.id as id1_5_1_,
        instructor0_.address as address2_2_0_,
        instructor0_.birth_date_time as birth_da3_2_0_,
        instructor0_.birth_date_time_zone_offset as birth_da4_2_0_,
        instructor0_.created_date as created_5_2_0_,
        instructor0_.day_off_time as day_off_6_2_0_,
        instructor0_.day_start_time as day_star7_2_0_,
        instructor0_.father_name as father_n8_2_0_,
        instructor0_.mother_name as mother_n9_2_0_,
        instructor0_.name as name10_2_0_,
        instructor0_.photo as photo11_2_0_,
        instructor0_.monthly_salary as monthly12_2_0_,
        instructor0_.updated_date as updated13_2_0_,
        instructor0_.version as version14_2_0_,
        vehicles1_.creation_date as creation2_5_1_,
        vehicles1_.instructor_id as instruct8_5_1_,
        vehicles1_.purchased_date_time as purchase3_5_1_,
        vehicles1_.purchased_date_zone_offset as purchase4_5_1_,
        vehicles1_.student_id as student_9_5_1_,
        vehicles1_.updated_date as updated_5_5_1_,
        vehicles1_.vechicle_type as vechicle6_5_1_,
        vehicles1_.vehicle_number as vehicle_7_5_1_,
        vehicles1_.instructor_id as instruct8_5_0__,
        vehicles1_.id as id1_5_0__ 
    from
        instructor instructor0_ 
    inner join
        vehicle vehicles1_ 
            on instructor0_.id=vehicles1_.instructor_id

В результате все инструкторы извлеченыиз db вместе с их транспортными средствами и после выполнения i.getVehicles () ни один запрос не переходит к db снова.Что должно быть правильным поведением.Я получаю это поведение с предложением JPQL join fetch.

Контрольный пример 2: пробовал то же самое с Criteria API, как показано ниже:

 @Test
        @Transactional
        @Rollback(false)
        public void fetchTest3() {
            CriteriaBuilder cb = em.getCriteriaBuilder();
            CriteriaQuery<Instructor> cq = 
            cb.createQuery(Instructor.class);
            Root<Instructor> root = cq.from(Instructor.class);
            root.join(Instructor_.vehicles);
            List<Instructor> instructorsWithCriteria = 
            em.createQuery(cq.distinct(true).select(root)).
            getResultList();
            print(instructorsWithCriteria);

    }

Запрос БД передан в БД для случая 2:

 select distinct instructor0_.id as id1_2_,
    instructor0_.address as address2_2_,
    instructor0_.birth_date_time as birth_da3_2_,
    instructor0_.birth_date_time_zone_offset as birth_da4_2_,
    instructor0_.created_date as created_5_2_,
    instructor0_.day_off_time as day_off_6_2_,
    instructor0_.day_start_time as day_star7_2_,
    instructor0_.father_name as father_n8_2_,
    instructor0_.mother_name as mother_n9_2_,
    instructor0_.name as name10_2_,
    instructor0_.photo as photo11_2_,
    instructor0_.monthly_salary as monthly12_2_,
    instructor0_.updated_date as updated13_2_,
    instructor0_.version as version14_2_ 
from
    instructor instructor0_ 
inner join
    vehicle vehicles1_ 
        on instructor0_.id=vehicles1_.instructor_id

** В результатевсе инструкторы взяты из БД.Как только я нажимаю i.getVehciles () в методе print, запрос на получение транспортных средств этого инструктора отправляется в db.То же самое происходит со всеми инструкторами один за другим.То же самое происходит и в случаях 3 и 4 ниже.

Что следует передать в предложении select в случаях 2, 3, 4, чтобы столбцы транспортных средств также были выбраны в запросе?

**
Тестовый случай 3: JPQL в левом соединении

        @Test
        @Transactional
        @Rollback(false)
        public void fetchTest2() {
        List<Instructor> instructorsJpqlLeftJoin = em
          .createQuery("select distinct i from Instructor i left join 
          i.vehicles v ", Instructor.class)
          .getResultList();
          print(instructorsJpqlLeftJoin);

        }

ДБ Запрос в дБ для случая 3:

  select
        distinct instructor0_.id as id1_2_,
        instructor0_.address as address2_2_,
        instructor0_.birth_date_time as birth_da3_2_,
        instructor0_.birth_date_time_zone_offset as birth_da4_2_,
        instructor0_.created_date as created_5_2_,
        instructor0_.day_off_time as day_off_6_2_,
        instructor0_.day_start_time as day_star7_2_,
        instructor0_.father_name as father_n8_2_,
        instructor0_.mother_name as mother_n9_2_,
        instructor0_.name as name10_2_,
        instructor0_.photo as photo11_2_,
        instructor0_.monthly_salary as monthly12_2_,
        instructor0_.updated_date as updated13_2_,
        instructor0_.version as version14_2_ 
    from
        instructor instructor0_ 
    left outer join
        vehicle vehicles1_ 
            on instructor0_.id=vehicles1_.instructor_id


Case 4 : Criteria API Left Join : 
          @Test
          @Transactional
          @Rollback(false)
    public void fetchTest4() {
    CriteriaBuilder cbLeftJoin = em.getCriteriaBuilder();
    CriteriaQuery<Instructor> cqLeftJoin = 
    cbLeftJoin.createQuery(Instructor.class);
    Root<Instructor> rootLeftJoin = cqLeftJoin.from(Instructor.class);
    rootLeftJoin.join(Instructor_.vehicles, JoinType.LEFT);
    List<Instructor> instructorsWithCriteriaLeftJoin = em
    .createQuery(cqLeftJoin.distinct(true).
    select(rootLeftJoin)).getResultList();
    print(instructorsWithCriteriaLeftJoin);

}

ДБ Запрос для случая 4:

 select
        distinct instructor0_.id as id1_2_,
        instructor0_.address as address2_2_,
        instructor0_.birth_date_time as birth_da3_2_,
        instructor0_.birth_date_time_zone_offset as birth_da4_2_,
        instructor0_.created_date as created_5_2_,
        instructor0_.day_off_time as day_off_6_2_,
        instructor0_.day_start_time as day_star7_2_,
        instructor0_.father_name as father_n8_2_,
        instructor0_.mother_name as mother_n9_2_,
        instructor0_.name as name10_2_,
        instructor0_.photo as photo11_2_,
        instructor0_.monthly_salary as monthly12_2_,
        instructor0_.updated_date as updated13_2_,
        instructor0_.version as version14_2_ 
    from
        instructor instructor0_ 
    left outer join
        vehicle vehicles1_ 
            on instructor0_.id=vehicles1_.instructor_id

Что мне делать в случае 2,3,4чтобы столбцы транспортных средств также были выбраны в том же запросе, чтобы второстепенные выборки не переходили в db?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...