java - 无法在 JPQL 查询中使用 left join 和 join fetch 来获取数据,并以实体图作为提示

标签 java mysql hibernate jpa entitygraph

我正在使用 Jpa 2.2 和 Hibernate 5.3.7 Final jar。以下是我的实体 并且测试用例的代码未正确执行:

讲师实体:

@Entity
@DynamicUpdate
@DynamicInsert
   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;
    **@OneToOne(mappedBy = "instructor", fetch = FetchType.LAZY, orphanRemoval = true, cascade = CascadeType.ALL)
    @JoinColumn(name = "proof_id")
    private IdProof idProof;
    @OneToMany(mappedBy = "instructor", orphanRemoval = true, cascade = CascadeType.ALL)
    private Set<Vehicle> vehicles = new HashSet<>();**

IdProof 实体:

@Entity
@Table(name = "id_proof_tbl")
@DynamicInsert
@DynamicUpdate
public class IdProof {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO, generator = "native")
    @GenericGenerator(name = "native", strategy = "native")
    @Column(updatable = false)
    private int id;
    @Version
    @Column(columnDefinition = "int(11) not null default 0")
    private int version;
    **@OneToOne(fetch = FetchType.LAZY)
    private Instructor instructor;**

车辆实体:

@Entity
@DynamicInsert
@DynamicUpdate
public class Vehicle {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO, generator = "native")
    @GenericGenerator(name = "native", strategy = "native")
    private int id;
    **@ManyToOne(fetch = FetchType.LAZY)
    private Instructor instructor;**
    **@OneToMany(mappedBy = "vehicle", fetch = FetchType.LAZY, orphanRemoval = true, cascade = CascadeType.ALL)
    private Set<Document> documents = new HashSet<>();**

和文档实体:

@Entity
@DynamicInsert
@DynamicUpdate
public class Document {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO, generator = "native")
    @GenericGenerator(name = "native", strategy = "native")
    private int id;    
    **@ManyToOne(fetch = FetchType.LAZY)
    private Vehicle vehicle;**

我正在从MySQL数据库中获取数据,代码如下所示 JUnit 测试:

 @Test
        @Rollback(false)
        @Transactional
        public void fetchPartialDataWithJPQLQueryWithEqualEntityGraph() {

**// Preparing Entity Graph to be passed as a hint .** 

        EntityGraph<Instructor> instructorGraph =   
          em.createEntityGraph(Instructor.class);
            instructorGraph.addAttributeNodes(Instructor_.idProof);
        Subgraph<Vehicle> vehcileSubgraph = 
            instructorGraph.addSubgraph(Instructor_.VEHICLES);
        vehcileSubgraph.addAttributeNodes(Vehicle_.documents);

**//Case 1:**   
        TypedQuery<Instructor> typedQueryJoinFetch = 
        em.createQuery(" select i from Instructor i "
                + " join fetch i.idProof id " 
                + " join fetch i.vehicles v " 
                + " join fetch v.documents vd ",
                Instructor.class);
         typedQueryJoinFetch.setHint("javax.persistence.fetchgraph", 
                                                     instructorGraph);
        List<Instructor> instructors 
                  =typedQueryJoinFetch.getResultList();


**//Case 2:** 
TypedQuery<Instructor> typedQueryLeftJoin = 
   em.createQuery(" select i from Instructor i "
                + " left join i.idProof id "  
                + " left join i.vehicles v " 
                + " left join v.documents vd ",
                Instructor.class);
        typedQueryLeftJoin.setHint("javax.persistence.fetchgraph", 
                                     instructorGraph);
        List<Instructor> instructorsWithLeftJoin = 
                                typedQueryLeftJoin.getResultList();


**// Case 3:**
    try {
        TypedQuery<Instructor> 
        typedQueryLeftJoinAndJoinFetchMixed = 
                   em.createQuery(" select i from Instructor i "
                                + " join fetch i.idProof id " 
                                + " left join i.vehicles v " 
                                + " join fetch v.documents vd ",
                                Instructor.class);
        typedQueryLeftJoinAndJoinFetchMixed.
           setHint("javax.persistence.fetchgraph", instructorGraph);
        List<Instructor> 
              instructorsWithLeftJoinAndJoinFetchMixed = 
                       typedQueryLeftJoinAndJoinFetchMixed
                                .getResultList();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }

                }


**Case 1 executes correctly and results in the inner join between the four 
         tables with below query:** 
    select
            instructor0_.id as id1_2_0_,
            idproof1_.id as id1_1_1_,
            vehicles2_.id as id1_5_2_,
            documents3_.id as id1_0_3_,
            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_,
            idproof1_.address as address2_1_1_,
            idproof1_.created_date as created_3_1_1_,
            idproof1_.father_name as father_n4_1_1_,
            idproof1_.instructor_id as instruc12_1_1_,
            idproof1_.is_foreigner as is_forei5_1_1_,
            idproof1_.mother_name as mother_n6_1_1_,
            idproof1_.name as name7_1_1_,
            idproof1_.proof_sequence_no as proof_se8_1_1_,
            idproof1_.sex as sex9_1_1_,
            idproof1_.updated_date as updated10_1_1_,
            idproof1_.version as version11_1_1_,
            vehicles2_.creation_date as creation2_5_2_,
            vehicles2_.instructor_id as instruct8_5_2_,
            vehicles2_.purchased_date_time as purchase3_5_2_,
            vehicles2_.purchased_date_zone_offset as purchase4_5_2_,
            vehicles2_.student_id as student_9_5_2_,
            vehicles2_.updated_date as updated_5_5_2_,
            vehicles2_.vechicle_type as vechicle6_5_2_,
            vehicles2_.vehicle_number as vehicle_7_5_2_,
            vehicles2_.instructor_id as instruct8_5_0__,
            vehicles2_.id as id1_5_0__,
            documents3_.name as name2_0_3_,
            documents3_.vehicle_id as vehicle_3_0_3_,
            documents3_.vehicle_id as vehicle_3_0_1__,
            documents3_.id as id1_0_1__ 
        from
            instructor instructor0_ 
        inner join
            id_proof_tbl idproof1_ 
                on instructor0_.id=idproof1_.instructor_id 
        inner join
            vehicle vehicles2_ 
                on instructor0_.id=vehicles2_.instructor_id 
        inner join
            document documents3_ 
                on vehicles2_.id=documents3_.vehicle_id

**Case 2 executes successfully and results in left outer join between 
four tables with below query:** 
  select
        instructor0_.id as id1_2_0_,
        idproof1_.id as id1_1_1_,
        vehicles2_.id as id1_5_2_,
        documents3_.id as id1_0_3_,
        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_,
        idproof1_.address as address2_1_1_,
        idproof1_.created_date as created_3_1_1_,
        idproof1_.father_name as father_n4_1_1_,
        idproof1_.instructor_id as instruc12_1_1_,
        idproof1_.is_foreigner as is_forei5_1_1_,
        idproof1_.mother_name as mother_n6_1_1_,
        idproof1_.name as name7_1_1_,
        idproof1_.proof_sequence_no as proof_se8_1_1_,
        idproof1_.sex as sex9_1_1_,
        idproof1_.updated_date as updated10_1_1_,
        idproof1_.version as version11_1_1_,
        vehicles2_.creation_date as creation2_5_2_,
        vehicles2_.instructor_id as instruct8_5_2_,
        vehicles2_.purchased_date_time as purchase3_5_2_,
        vehicles2_.purchased_date_zone_offset as purchase4_5_2_,
        vehicles2_.student_id as student_9_5_2_,
        vehicles2_.updated_date as updated_5_5_2_,
        vehicles2_.vechicle_type as vechicle6_5_2_,
        vehicles2_.vehicle_number as vehicle_7_5_2_,
        vehicles2_.instructor_id as instruct8_5_0__,
        vehicles2_.id as id1_5_0__,
        documents3_.name as name2_0_3_,
        documents3_.vehicle_id as vehicle_3_0_3_,
        documents3_.vehicle_id as vehicle_3_0_1__,
        documents3_.id as id1_0_1__ 
    from
        instructor instructor0_ 
    left outer join
        id_proof_tbl idproof1_ 
            on instructor0_.id=idproof1_.instructor_id 
    left outer join
        vehicle vehicles2_ 
            on instructor0_.id=vehicles2_.instructor_id 
    left outer join
        document documents3_ 
            on vehicles2_.id=documents3_.vehicle_id

但我只想获取数据库中存在 IdProofs 的讲师以及数据库中存在文档的唯一车辆。所以我编写了案例 3​​。但是案例 3 导致以下异常:

 java.lang.IllegalArgumentException: org.hibernate.QueryException: query specified join fetching, but the owner of the fetched association was not present in the select list [FromElement{explicit,not a collection join,fetch join,fetch non-lazy properties,classAlias=vd,role=com.katariasoft.technologies.jpaHibernate.college.data.entity.Vehicle.documents,tableName=document,tableAlias=documents3_,origin=vehicle vehicles2_,columns={vehicles2_.id ,className=com.katariasoft.technologies.jpaHibernate.college.data.entity.utils.Document}}] [ select i from com.katariasoft.technologies.jpaHibernate.college.data.entity.Instructor i  join fetch i.idProof id left join i.vehicles v  join fetch v.documents vd ]

请告诉我如何满足案例 3 的获取要求 所有具有 IDProofs 的教练都存在于数据库中,并且他们唯一的车辆具有数据库中存在的文档。

最佳答案

您需要在没有 fetch 的情况下加入文档,因为 hibernate 正在尝试使用该关键字为不存在的车辆获取这些文件。

   em.createQuery(" select i from Instructor i "
            + " join fetch i.idProof id " 
            + "left join i.vehicles v " 
            + " join v.documents vd ",
            Instructor.class);

现在,在获得结果后,在处理/访问车辆文档之前,您只需检查 Instructor.vehicles 是否为空,如果为空则不继续。

关于java - 无法在 JPQL 查询中使用 left join 和 join fetch 来获取数据,并以实体图作为提示,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54323022/

相关文章:

mysql - Django mysql 查询

postgresql - 序列不存在时存在 - Postgres/Spring Boot

java - 操作栏背景大小,Android

java - 谷歌应用引擎500未知错误

java - 使用 bigquery java api 获得较小的查询结果

mysql - 选择日期范围外的行(与 BETWEEN 语句相反)

mysql - 在别名连接字段中使用 WHERE 会出现 'unknown column' 错误

hibernate - 方法在 Grails 应用程序之外使用

java - spring boot + jpa 延迟获取

java - 从可以在 Linux 中打开的文件路径创建文件