JPQL左联接和条件API联接(左和内)引发了额外的数据库查询以初始化关联

时间:2019-01-28 11:56:49

标签: jpa-2.0 jpql criteria-api

我下面有两个实体。教师实体与Vehicle实体之间的关系为toToy。

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连接提取子句。

            @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());
                });

        });

案例1的DB查询进入数据库:

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的db查询进入db:

 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

**因此,所有讲师都被db取代。我一击中 打印方法中的i.getVehciles()查询以获取此讲师的车辆去db。所有讲师都一一对应。 下面的情况3和4也会发生相同的行为。

在情况2、3、4的select子句中应该传递什么,以便在查询中也选择车辆列?

**
  测试案例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的db查询到db:

  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的db查询:

 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的情况下我应该怎么做,以便在同一查询中也选择了Vehicles列,这样就不会再有次要的选择进入数据库了?

0 个答案:

没有答案