簡體   English   中英

有條件地獲取加入 hibernate 或將實體設計更改為有條件地獲取子項?

[英]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;
}

一種三向映射。 上面的實體設計說的是:

  1. 一個組織可以舉辦許多活動
  2. 一個事件可以有多個事件值
  3. 一個組織可以有許多任務
  4. 一項分配只能映射到一個組織,並且在該組織的事件中,它應該只有一個事件值(但根據上面的實體設計,它可以具有一組不直接映射到分配的值

所以,我試圖查詢這樣的東西。

@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 解決方案?

連接提取不允許WITHON子句的原因非常簡單。 Hibernate 適用於托管實體,這意味着,一旦實體由當前持久性上下文管理,對這些對象所做的更改將在事務結束時刷新回數據庫。

現在,如果允許您在連接提取中使用WITHON子句,則查詢本身可能會更改集合的托管 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM