我下面有两个实体。教师实体与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列,这样就不会再有次要的选择进入数据库了?