【问题标题】:Translate SQL Query to JPQL - @ManyToMany join将 SQL 查询转换为 JPQL - @ManyToMany 连接
【发布时间】:2020-08-10 19:44:06
【问题描述】:

我正在尝试将 @Query("...", native=true) Spring Data Jpa 注释中的 SQL 本机查询用法转换为同一注释中的 JPQL 查询用法。 SQL 查询:

select d.id as doctorId, d.firstName as doctorFirstName, d.lastName as doctorLastName, d.title as doctorTitle, 
d.email as doctorEmail, v.id as id, v.dateFrom as dateFrom, v.dateTo as dateTo, v.status as status,
md.id as medicalServicesId, md.service as medicalServicesService, md.price as medicalServicesPrice 
from Visit v 
left outer join Doctor d on v.doctor_id=d.id 
left outer join visit_medical_services vms on v.id=vms.medical_services_id 
left outer join MedicalService md on vms.visit_id=md.id 
where d.id= :doctorId and v.status= :status and v.dateFrom>= :dateFrom and v.dateTo<= :dateTo

我使用的是 Spring Projected Interface,这就是为什么列别名被命名为 like this。

现在我想用 JPQL 获得完全相同的结果 - 项目列表。我所做的尝试是这样的:

    @Query("select d.id as doctorId, d.firstName as doctorFirstName, d.lastName as doctorLastName, d.title as doctorTitle, d.email as doctorEmail, " +
            "v.id as id, v.dateFrom as dateFrom, v.dateTo as dateTo, v.status as status, md.id as medicalServicesId, md.service as medicalServicesService, md.price as medicalServicesPrice \n" +
            "from Visit v \n" +
            "left outer join Doctor d on v.doctor.id=d.id \n" +
            "left outer join v.medicalServices vms on vms.id=v.id \n" +
            "left outer join MedicalService md on md.id=vms.id \n" +
            "where d.id= :doctorId and v.status= :status and v.dateFrom>= :dateFrom and v.dateTo<= :dateTo")
    List<VisitInfoWithPatientAndMedServices3joins> getAllVisitInfoWithPatientAndMedicalServicesJpqlQuery
    (@Param("doctorId") Long doctorId, @Param("status") VisitStatus status, @Param("dateFrom") LocalDateTime dateFrom, @Param("dateTo") LocalDateTime dateTo, Pageable pageable);

这里是从 JPQL 翻译过来的 SQL。

select doctor1_.id as col_0_0_, doctor1_.firstName as col_1_0_, doctor1_.lastName as col_2_0_, doctor1_.title as col_3_0_, doctor1_.email as col_4_0_, visit0_.id as col_5_0_, visit0_.dateFrom as col_6_0_, visit0_.dateTo as col_7_0_, visit0_.status as col_8_0_, medicalser4_.id as col_9_0_, medicalser4_.service as col_10_0_, medicalser4_.price as col_11_0_ 
from Visit visit0_ 
left outer join  
(visit_medical_services medicalser2_ left outer join MedicalService medicalser3_ on medicalser2_.visit_id=medicalser3_.id) on visit0_.id=medicalser2_.medical_services_id 
and (medicalser3_.id=visit0_.id) 
left outer join Doctor doctor1_ on (visit0_.doctor_id=doctor1_.id) 
left outer join MedicalService medicalser4_ on (medicalser4_.id=medicalser3_.id) where doctor1_.id=? and visit0_.status=? and visit0_.dateFrom>=? and visit0_.dateTo<=? limit ?

这里的问题是,它从@ManyToMany 关系(visit_medical_services)返回列,但只针对第一个对象。来自 Postman 的 Json 响应如下:

[
    {
        "id": 1,
        "status": "PAID",
        "dateFrom": "2019-04-10T08:00:00",
        "dateTo": "2019-04-10T08:30:00",
        "medicalServicesId": 1,
        "medicalServicesService": "Visit",
        "medicalServicesPrice": 100.0,
        "doctorLastName": "James",
        "doctorFirstName": "Alex",
        "doctorEmail": "james@gmail.com",
        "doctorId": 1,
        "doctorTitle": "dr n. md."
    },
    {
        "id": 2,
        "status": "PAID",
        "dateFrom": "2019-04-10T09:00:00",
        "dateTo": "2019-04-10T09:30:00",
        "medicalServicesId": null,
        "medicalServicesService": null,
        "medicalServicesPrice": null,
        "doctorLastName": "James",
        "doctorFirstName": "Alex",
        "doctorEmail": "james@gmail.com",
        "doctorId": 1,
        "doctorTitle": "dr n. md."
    }
]

我尝试在 Workbench 中使用使用 JPQL 的翻译 SQL 查询,因为我使用的是 MySQL 数据库,结果是相同的 - 第一个对象是正确的,其余的在映射的 @ManyToMany 列中具有空值。 这是我的实体类,如果它会让这个问题更容易一点:

public class Visit {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    Long id;
    LocalDateTime dateFrom;
    LocalDateTime dateTo;
    @Enumerated(EnumType.STRING)
    VisitStatus status;
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "doctor_id", referencedColumnName = "id", nullable = true)
    @JsonManagedReference
    Doctor doctor;
    @ManyToOne(fetch = FetchType.LAZY)
    @JsonManagedReference
    @JoinColumn(name = "patient_id", referencedColumnName = "id", nullable = true)
    Patient patient;
    @ManyToMany
    @JsonManagedReference
    @JoinTable(
            name = "visit_diseases",
            joinColumns = @JoinColumn(
                    name = "disease_id", referencedColumnName = "id"),
            inverseJoinColumns = @JoinColumn(
                    name = "visit_id", referencedColumnName = "id"))
    List<Disease> diseases;
    @ManyToMany
    @JsonManagedReference
    @JoinTable(
            name = "visit_medical_services",
            joinColumns = @JoinColumn(
                    name = "medical_services_id"),
            inverseJoinColumns = @JoinColumn(
                    name = "visit_id"))
    Set<MedicalService> medicalServices;
    String mainSymptoms;
    String treatment;
    String allergy;
    String addiction;
    String comment;
}

和医疗服务:

public class MedicalService {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    Long id;
    String service;
    Float price;

    @ManyToMany(mappedBy = "medicalServices", fetch = FetchType.EAGER)
    private Set<Visit> visits;

    public MedicalService(Long id, String service, float price) {
        this.id = id;
        this.service = service;
        this.price = price;
    }
}

有人可以看一下并向我解释这里有什么不正常的地方吗?我想要实现的是让 JPQL 生成 THE SAME SQL 查询。甚至有可能吗?请帮帮我...

【问题讨论】:

  • 是否可以通过打开 show-sql 来共享控制台中生成的 jpql gtting 的等效 sql 查询?
  • 当然,我刚刚编辑了问题,在 JPQL @Query 下面你可以看到生成的 SQL。

标签: sql spring hibernate spring-data-jpa jpql


【解决方案1】:

您的查询中有一些错误。请改用以下内容

@Query("select d.id as doctorId, d.firstName as doctorFirstName, d.lastName as doctorLastName, d.title as doctorTitle, d.email as doctorEmail, " +
        "v.id as id, v.dateFrom as dateFrom, v.dateTo as dateTo, v.status as status, md.id as medicalServicesId, md.service as medicalServicesService, md.price as medicalServicesPrice \n" +
        "from Visit v \n" +
        "left outer join v.doctor d \n" +
        "left outer join v.medicalServices md \n"
        "where d.id= :doctorId and v.status= :status and v.dateFrom>= :dateFrom and v.dateTo<= :dateTo")
List<VisitInfoWithPatientAndMedServices3joins> getAllVisitInfoWithPatientAndMedicalServicesJpqlQuery
(@Param("doctorId") Long doctorId, @Param("status") VisitStatus status, @Param("dateFrom") LocalDateTime dateFrom, @Param("dateTo") LocalDateTime dateTo, Pageable pageable);

【讨论】:

  • “on 部分可能是不必要的” - 确实如此。没有这部分,它工作完美,它不工作。请编辑您的答案,我会将其标记为解决方案。顺便说一句,非常感谢!
猜你喜欢
  • 1970-01-01
  • 2011-09-29
  • 2021-10-09
  • 2011-06-12
  • 2019-07-13
  • 1970-01-01
  • 2021-02-15
  • 2013-09-17
  • 2017-10-29
相关资源
最近更新 更多