简体   繁体   English

无法通过左联接获取数据,并且无法在JPQL查询中以整笔图作为提示将联接合并在一起

[英]Not able to fetch data with left join and join fetch together in JPQL query with entiy graphs as a hint

I am using Jpa 2.2 with Hibernate 5.3.7 final jar. 我正在将Jpa 2.2与Hibernate 5.3.7最终版jar一起使用。 Below are my entities and code for the test case is not executing correctly: 以下是我的实体,该测试用例的代码未正确执行:

Instructor Entity : 讲师实体:

@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: 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;**

Vehicle Entity : 车辆实体:

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

And Documents Entity : 和文件实体:

@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;**

I am fetching data from MySQL database with code described as below as a JUnit Test: 我正在使用下面描述的代码作为JUnit测试从MySQL数据库中获取数据:

 @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

But I want to fetch only those instructors having IdProofs present in the database along with their only vehicles having documents present in the database. 但是我只想获取那些在数据库中具有IdProofs的讲师,以及他们仅有的在数据库中具有文档的车辆。 So I coded case 3. But Case 3 results in below exception: 所以我编写了案例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 ]

Please let me know how I can fulfil my case 3 requirement to fetch All Instructors having IdProofs present In DB along with their only vehicles having documents present in DB. 请让我知道如何满足我的情况3的要求,以获取DB中存在IdProof的所有讲师以及DB中存在文档的唯一载具。

You would need to join the document without the fetch as hibernate is trying to fetch these for a non-existant vehicle also with that keyword. 您可能需要不带fetch就加入文档,因为休眠状态也试图使用该关键字为不存在的车辆获取这些文件。

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

Now after you get the results, before processing / accessing the documents of a vehicle you would simply check whether Instructor.vehicles is empty and not proceed if true. 现在,在获得结果之后,在处理/访问车辆文档之前,您只需检查Instructor.vehicles是否为空,如果为true,就不会继续。

  Below code fetches Only those instrcutors having IdProof present in
  DB . If No Instructor is having idProof present in db then written
  query will return empty List as there is inner join between
  Instructor and IdProof . 

  All Instructors not having any vehicle will also be fetched and their
  vehicle list  will be initialised as empty.

  All vehicle not having any document will also be fetched along with
  vehicles having atleast one document . Vehicles not having any
  document can be avoided in code while processing data . 

  But if inner join is created between Vehicle and document and if
  there is no  document present in db then it will make the complete
  result empty . As final inner join will be applied on join results
  evaluted till yet in db on first three tables Instructor , IdProof and 
  Vehcile.


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

                        }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM