[英]JPA query to get most recent child of child
我有一個包含實體 Plane、MaintenanceCheck、Transponder 的 Soring/JPA 項目。
就 ORM dsetup 而言,Plane 有許多 MaintenanceChecks。 大多數飛機只獲得 1 個轉發器(在維護檢查期間完成),但偶爾飛機可能會更換轉發器。
我還使用 ModelMapper 和 DTO 來查看視圖。
實體
飛機
@Entity
@Data
public class Plane {
@Id
@GeneratedValue(strategy = IDENTITY)
private Long id;
@Column(unique = true)
private String name;
@JsonIgnore
@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, mappedBy = "plane")
private List<MaintCheck> listMaintCheck = new ArrayList<>();
維護檢查
@Entity
@Data
public class MaintCheck {
@Id
@GeneratedValue(strategy = IDENTITY)
private Long id;
@ManyToOne(fetch = FetchType.LAZY, optional = false)
private Plane plane;
private LocalDate checkDate;
@JsonIgnore
@OneToMany (cascade = { CascadeType.DETACH, CascadeType.MERGE, CascadeType.MERGE, CascadeType.REFRESH}, orphanRemoval = true, mappedBy = "maintCheck")
private List<Transponder> listTransponder = new ArrayList<>();
轉發器
@Entity
@Data
public class Transponder {
@Id
@GeneratedValue(strategy = IDENTITY)
private Long id;
private String code;
@ManyToOne(fetch = FetchType.LAZY, optional = true)
private MaintCheck maintCheck;
飛機儀表板 DTO
@Data
public class PlaneDashboardDTO {
private String name; // plane name
private LocalDate last_check; // last maintenance date
private String code; // most recent transponder code
}
當真正的關系存在於轉發器和飛機之間時,為什么我要以這種方式構建實體(維護檢查恰好發生轉發器更改時)。 因為維護檢查已經有一個日期字段,如果轉發器只通過維護檢查進行更改,那么我最終不會將日期存儲兩次。
TABLE PLANE
ID, NAME
1, NC899
2, N345C
TABLE MAINT CHECK
ID, NAME, DATE, PLANE_ID
1, Check 1, 2022-03-01, 1
2, Check 2, 2022-03-05, 2
3, Check 3, 2022-03-08, 1
4, Check 4, 2022-03-10, 2
5, Check 5, 2022-03-11, 1
TABLE TRANSPONDER
ID, CODE, MAINT_ID
1, DF000AB, 1
2, AB000DC, 3
3, AE000DE, 4
請注意,並非每次維護檢查都有應答器記錄。 事實上大多數不
問題假設這是構造數據的正確方法(我不確定它是)如何將給定平面 ID 的當前(最新)轉發器獲取到 PlaneDashboardDTO 中? (我假設這將在服務層使用 JPQL 或 SQL 完成)
在上面的例子中,我將檢索飛機 ID 1 的最新轉發器,它有維護檢查 ID 1,3, 5。只有維護檢查 1 和 3 在飛機 ID 1 的轉發器表上,因為維護檢查 3 有最近日期,當前轉發器代碼是 AB000DE。
這里有一個小提琴: https://www.db-fiddle.com/f/pxvtyUrQWz3d7s6tdQFT1B/1
如果不在數據庫上進行測試,我會像這樣嘗試 SQL:
select transponder.code
from transponder
join maint_check on maint_check.id=transponder.maint_id
join plane on plane.id=maint_check.plane_id
where plane.id=1
and maint_check.date=(select max(m.date) from maint_check m join transponder t on t.maint_id=m.id and m.plane_id=1)
最后,我決定讓 Transponder 成為 Plane 的直接子代更好。 即飛機(一個)到轉發器(許多)。
然后將數據從 Plane 和 Transponder 獲取到 DTO 的過程位於服務層。
平面服務實現
@Override
public PlaneSummaryDTO getPlaneSummaryDTOById(Long id) {
Plane plane = this.get(id);
PlaneSummaryDTO planeSummaryDTO = new PlaneSummaryDTO();
List<Transponder> listTransponder;
listTransponder = plane.getListTransponder();
Transponder newest = listTransponder.stream().max(Comparator.comparing(Transponder::getDateInserted)).get();
ModelMapper mapper = new ModelMapper();
planeSummaryDTO = modelMapper.map(get(id), PlaneSummaryDTO.class);
planeSummaryDTO.setPitCode(newest.getCode());
return planeSummaryDTO;
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.