簡體   English   中英

使用 JPA/Hibernate 構造函數表達式防止“n+1 選擇”?

[英]Prevent “n+1 selects” with JPA/Hibernate constructor expression?

我有兩個實體, ItemData ,以及一個 DTO 類ItemData ItemDataItemData組成,沒有 JPA 映射。 為了檢索填充的 ItemData 列表,我在 JPQL 中使用了一個構造函數表達式:

select new my.package.ItemData(i, d)
from Item i, Data d
where i.id = d.itemId

這就是 Hibernate 正在做的事情:它不是同時獲取ItemData ,而是先獲取它們的 ID,然后在n 個單獨的 select 語句中獲取數據。 有沒有辦法改變這種行為?

Hibernate:
    select
        item0_.id as col_0_0_,
        data1_.id as col_1_0_ 
    from
        ITEM item0_,
        DATA data1_

Hibernate: 
    select
        item0_.no as no1_0_,
        item0_.description as description1_0_,
        item0_.organic as bio1_0_,
        item0_.gluten as gluten1_0_,
        item0_.laktose as laktose1_0_
    from
        ITEM item0_ 
    where
        item0_.id=?

Hibernate: 
    select
        data0_.amount as amount1_3_0_,
        data0_.avg as avg3_0_,
        data0_.total as total3_0_
    from
        DATA data0_ 
    where
        data0_.id=?

Hibernate: 
    select
        item0_.no as no1_0_,
        item0_.description as description1_0_,
        item0_.organic as bio1_0_,
        item0_.gluten as gluten1_0_,
        item0_.laktose as laktose1_0_
    from
        ITEM item0_ 
    where
        item0_.id=?

Hibernate: 
    select
        data0_.amount as amount1_3_0_,
        data0_.avg as avg3_0_,
        data0_.total as total3_0_
    from
        DATA data0_ 
    where
        data0_.id=?

...and so on...        

使用左連接獲取怎么樣?
我承認我沒有使用 CTOR 表達式,但是當我需要獲取父實體及其子實體時,我使用了 left join fetch 並且它總是像魅力一樣工作。
我只能假設既然我們在這里處理對象的構造,
Hibernate 不“想要”留下“部分構造”的對象(或者比方說 - 處於“延遲評估狀態”的對象),並且由於您沒有使用“左連接提取”執行“急切提取”,因此它執行 N +1 獲取:
首先它獲取所有的 ID,然后對每個相關的 ID 執行另一個獲取。
在此處閱讀有關左連接提取的更多信息(只需在頁面上查找“左連接提取”即可)

這是Blaze-Persistence Entity Views的完美用例。

我創建了該庫以允許在 JPA 模型和自定義接口或抽象類定義的模型之間輕松映射,例如類固醇上的 Spring Data Projections。 這個想法是您按照自己喜歡的方式定義目標結構(域模型),並通過 JPQL 表達式將屬性(getter)映射到實體模型。

我想你的實體模型看起來像這樣?

@Entity
class Item {
  @Id Long id;
  String description;
  @OneToMany(mappedBy = "item")
  Data data;
  ...
}
@Entity
class Data {
  @Id Long id;
  @ManyToOne Item item;
  Long amount;
  BigDecimal avg;
  ...
}

使用 Blaze-Persistence Entity-Views 的用例的 DTO 模型可能如下所示:

@EntityView(Item.class)
public interface ItemData {
    @IdMapping
    Long getNo();
    String getDescription();
    @Mapping("SUM(data.amount)")
    Long getAmount();
}

查詢是將實體視圖應用於查詢的問題,最簡單的只是按 id 查詢。

ItemData a = entityViewManager.find(entityManager, ItemData.class, id);

Spring Data 集成允許您像使用 Spring Data Projections 一樣使用它: https : //persistence.blazebit.com/documentation/entity-view/manual/en_US/index.html#spring-data-features

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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