我想做的是使用Spring Data Jpa中的JpaRepository接口,用3种不同的方法编写相同的查询:
- 命名方法策略。
- @Query使用JPQL。
- @Query本地SQL。
在这里,您可以看到我创建了Visit Entity,并选择了所有相关关系。
public class Visit {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "id")
long visitId;
LocalDateTime dateFrom;
LocalDateTime dateTo;
@Enumerated(EnumType.STRING)
VisitStatus status;
@ManyToOne(fetch = FetchType.EAGER)
@JsonManagedReference
Doctor doctor;
@ManyToOne
@JsonManagedReference
Patient patient;
@ManyToMany
@JsonManagedReference
List<Disease> diseases;
@ManyToMany
@JsonManagedReference
List<MedicalService> medicalServices;
String mainSymptoms;
String treatment;
String allergy;
String addiction;
String comment;
我正在使用Project Lombok,以便我不需要复制类上方的所有注释。 所以这里是实验。我创建了一个方法,应该返回在给定时间间隔内特定医生的所有就诊记录。
这是我编写的方法:
List<VisitView> findByDoctorIdAndStatusAndDateFromGreaterThanEqualAndDateToLessThanEqual
(long doctorId, VisitStatus visitStatus, LocalDateTime dateFrom, LocalDateTime dateTo);
正如您所看到的,我已经使用Spring Projections实现了VisitView接口。
这就是它:
public interface VisitView {
long getDoctorId();
// Doctor getDoctor();
// interface Doctor {
// String getFirstName();
// String getLastName();
// }
String getDoctorFirstName();
String getDoctorLastName();
Long getPatientId();
long getVisitId();
LocalDateTime getDateFrom();
LocalDateTime getDateTo();
VisitStatus getStatus();
}
使用这种方法,一切正常。我可以通过 Doctor Entity 类的 getter 方法和内置的 Doctor 接口两种方式获取医生 firstName 和 lastName 字段。下面是使用项目接口的两个 JSON 示例:
[
{
"status": "PAID",
"visitId": 395,
"dateTo": "2019-04-10T08:30:00",
"dateFrom": "2019-04-10T08:00:00",
"doctorId": 401,
"patientId": 394,
"doctorFirstName": "Aleksander",
"doctorLastName": "Ziółko"
}
]
[
{
"status": "PAID",
"visitId": 395,
"dateTo": "2019-04-10T08:30:00",
"doctor": {
"firstName": "Aleksander",
"lastName": "Ziółko"
},
"dateFrom": "2019-04-10T08:00:00",
"doctorId": 401,
"patientId": 394
}
]
现在我想使用@Query和JPQL以及本地SQL实现相同的结果。因此,我打印出了这个方法生成的SQL,并尝试将其与@Query注释一起使用。下面是它的代码:
@Query + 本地SQL:
@Query(value = "SELECT d.id as doctorId, d.firstName as firstName, d.lastName as lastName, p.id as patientId, v.id as visitId, v.dateFrom as dateFrom, v.dateTo as dateTo, v.status as status \n" +
"FROM visit v \n" +
"LEFT OUTER JOIN doctor d on v.doctor_id=d.id \n" +
"LEFT OUTER JOIN users ud on d.id=ud.id \n" +
"LEFT OUTER JOIN patient p on v.patient_id=p.id \n" +
"LEFT OUTER JOIN users up on p.id=up.id \n" +
"where d.id= :doctorId and v.status= :status and v.dateFrom>= :dateFrom and v.dateTo<= :dateTo ", nativeQuery = true)
List<VisitView> searchForDoctorsVisitByStatusAndTimeIntervalNativeQuery(
@Param("doctorId") long doctorId, @Param("status") String status, @Param("dateFrom") LocalDateTime dateFrom, @Param("dateTo") LocalDateTime dateTo);
@Query + JPQL:
@Query("SELECT d.id as doctorId, d.firstName as firstName, d.lastName as lastName, p.id as patientId, v.visitId as visitId, v.dateFrom as dateFrom, v.dateTo as dateTo, v.status as status \n" +
"FROM Visit v \n" +
"LEFT OUTER JOIN Doctor d ON v.doctor.id=d.id \n" +
"LEFT OUTER JOIN Patient p ON v.patient.id=p.id \n" +
"WHERE d.id= :doctorId AND v.status= :status AND v.dateFrom>= :dateFrom AND v.dateTo<= :dateTo")
List<VisitView> searchForDoctorsVisitByStatusAndTimeIntervalJqplQuery(
@Param("doctorId") long doctorId, @Param("status") VisitStatus status, @Param("dateFrom") LocalDateTime dateFrom, @Param("dateTo") LocalDateTime dateTo);
这两个查询从VisitView返回带有null值的getter或Doctor接口的JSON:
[
{
"status": "PAID",
"visitId": 395,
"dateTo": "2019-04-10T08:30:00",
"dateFrom": "2019-04-10T08:00:00",
"doctorId": 401,
"patientId": 394,
"doctorFirstName": null,
"doctorLastName": null
}
]
[
{
"status": "PAID",
"visitId": 395,
"dateTo": "2019-04-10T08:30:00",
"doctor": null,
"dateFrom": "2019-04-10T08:00:00",
"doctorId": 401,
"patientId": 394
}
]
我已经尝试了许多版本的Hibernate,因为我读到很多不同版本出现的错误。我试图按照字母顺序对选定字段进行分组,因为我在另一个问题中发现了这个提示。我尝试使用@JoinColumn注释,因为建议这样做,但也没有帮助。
现在我变得疯狂,因为我无法弄清楚为什么它不起作用。 有人能帮帮我吗?
Hibernate核心版本 -> 5.4.14.Final
Hibernate ORM搜索版本 -> 5.11.5.Final
编辑: 上面的问题已经解决,但是.. 我有另一个关于这个主题的问题。
实体Visit与MedicalServices处于@ManyToMany关系。现在我想拉取这个列表,所以我投影了另一个接口:
public interface VisitInfoWithPatientAndMedServices {
LocalDateTime getDateFrom();
LocalDateTime getDateTo();
VisitStatus getStatus();
// long getMedicalServicesId();
// String getMedicalServicesService();
// float getMedicalServicesPrice();
List<MedicalService> getMedicalServices();
interface MedicalService {
String getId();
String getService();
float getPrice();
}
}
这个接口使用命名方法策略,只返回一个包含医疗服务列表的对象。以下是Postman返回的JSON格式数据:
[
{
"status": "PAID",
"medicalServices": [
{
"id": "3",
"service": "Something",
"price": 250.0
},
{
"id": "4",
"service": "USG",
"price": 400.0
}
],
"dateTo": "2019-04-10T08:30:00",
"dateFrom": "2019-04-10T08:00:00"
}
]
但是我仍然不能正确使用原生SQL和@Query注释。我知道可以使用此问题的解决方案来获取它,您可以在上述VisitInfoWithPatientAndMedServices接口中看到已注释掉它,并且它可以工作,但它返回的不是一个带有医疗服务列表的访问对象,而是两个相同的对象,每个对象都有一个医疗服务。它看起来像这样:
{
"dateTo": "2019-04-10T08:30:00",
"dateFrom": "2019-04-10T08:00:00",
"medicalServicesId": 3,
"medicalServicesPrice": 250.0,
"medicalServicesService": "Something",
"status": "PAID"
},
{
"dateTo": "2019-04-10T08:30:00",
"dateFrom": "2019-04-10T08:00:00",
"medicalServicesId": 4,
"medicalServicesPrice": 400.0,
"medicalServicesService": "USG",
"status": "PAID"
}
]
它的工作原理就像在Workbench中一样,因为我正在使用MySQL。
我能否采用命名方法策略和@Query注释(本地SQL和JPQL)来获得相同的JSON响应?