[英]Fetch join hibernate conditionally or change the entity design to conditional fetch on children?
我知道一個事實,hibernate 不允許使用 fetch join 子句
我正在使用 spring 數據 jpa 和 postgres。
這是我的實體的設計方式
public class Organisation {
@Id
private Long id;
@OneToMany(mappedBy = "organisation", cascade = CascadeType.ALL)
@LazyCollection(LazyCollectionOption.EXTRA)
private Set<Assignment> assignments = new HashSet<>();
@OneToMany(mappedBy = "organisation", cascade = CascadeType.ALL)
private List<Event> events;
}
public class Event {
@Id
private Long id;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "organisations_id", nullable = false)
private Organisation organisation;
@OneToMany(mappedBy = "event", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private Set<EventValue> eventValues = new HashSet<>();
}
public class EventValue {
@Id
private Long id;
@ManyToOne(fetch = FetchType.LAZY, optional = false)
@JoinColumn(name = "event_id")
private Event Event;
@ManyToOne(fetch = FetchType.LAZY, optional = false)
@JoinColumn(name = "assignment_id")
private Assignment assignment;
}
public class Assignment {
@Id
private Long id;
@OneToMany(mappedBy = "assignment", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private Set<EventValue> eventValues = new HashSet<>();
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "organisation_id", nullable = false)
private Organisation organisation;
}
一種三向映射。 上面的實體設計說的是:
所以,我試圖查詢這樣的東西。
@Query("select assignment from Assignment left join fetch assignment.organisation org
left join fetch org.event event left join fetch event.eventValues eventValue
with eventValue.assignment.id=?1 where assignment.id=?1)
Assignment getByAssignmentId(Long id);
我想通過查詢實現什么?
使用給定(id)-> 組織-> 活動列表獲取分配,其中HashSet僅包含一個映射到分配的活動值。
由於在 fetch join 上使用 with 子句,查詢顯然會失敗。 我不知何故覺得實體有 3 路依賴,所以它可能是錯誤的。
我不想使用通用 jdbcTemplate 解決方案或 SqlResultMapping 解決方案,我們需要手動進行某種投影和設置值。 是否有解決此問題的 ORM 解決方案?
連接提取不允許WITH
或ON
子句的原因非常簡單。 Hibernate 適用於托管實體,這意味着,一旦實體由當前持久性上下文管理,對這些對象所做的更改將在事務結束時刷新回數據庫。
現在,如果允許您在連接提取中使用WITH
或ON
子句,則查詢本身可能會更改集合的托管 state,這將導致 UPDATE/DELETE 語句將集合更改刷新回來。 由於這是完全出乎意料的,但卻是必要的副作用,因此是不允許的。
話雖如此,這是Blaze-Persistence Entity Views的完美用例。
Blaze-Persistence 是 JPA 之上的查詢構建器,它支持 JPA model 之上的許多高級 DBMS 功能。 我在它上面創建了實體視圖,以便在 JPA 模型和自定義接口定義模型之間輕松映射,例如 Spring 數據投影。 這個想法是您以您喜歡的方式定義您的目標結構,並通過 JPQL 表達式將 map 屬性(getter)定義到實體 model。 由於屬性名稱用作默認映射,因此您通常不需要顯式映射,因為 80% 的用例是擁有作為實體 model 子集的 DTO。
model 的 DTO 映射看起來很簡單,如下所示
@EntityView(Assignment.class)
interface AssignmentDto {
Long getId();
OrganisationDto getOrganisation();
}
@EntityView(Organisation.class)
interface OrganisationDto {
Long getId();
List<EventDto> getEvents();
}
@EntityView(Event.class)
interface EventDto {
Long getId();
@Mapping("eventValues[assignment.id = VIEW_ROOT(id)]")
EventValueDto getEventValue();
}
@EntityView(EventValue.class)
interface EventValueDto {
Long getId();
// Other stuff
}
JOIN 條件在映射表達式eventValues[assignment.id = VIEW_ROOT(id)]
中建模,它轉換為您所期望的。
查詢是將實體視圖應用於查詢的問題,最簡單的就是通過 id 進行查詢。
AssignmentDto dto = entityViewManager.find(entityManager, AssignmentDto.class, id);
但是 Spring 數據集成允許您幾乎像 Spring 數據投影一樣使用它: https://persistence.blazebit.com/documentation/entity-view/mandata-features_html/index。
它只會獲取您告訴它獲取的映射。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.