2015-06-23 42 views
0

我正在使用Spring Data JPA(Hibernate inside)。我有兩個實體測驗和問題。一對多關係。測驗有問題清單。我如何獲得有關測驗的信息和問題列表的大小?如果我寫這樣的:OneToMany:獲取集合的大小

Quiz quiz = quizRepository.findOne(1); 
int questionCount = quiz.getQuestions().size(); 

休眠產生兩個疑問:

  1. 約測驗
  2. 選擇信息
  3. 選擇所有問題

但我需要問題的唯一測驗信息和大小。

如何在沒有第二次選擇的情況下做到這一點?

回答

0

從您的問題中不清楚您是僅僅希望避免第二次SQL查詢還是希望完全避免將問題加載到內存中。

正如其他地方所指出的那樣,您可以通過在關係本身或通過加載測驗的條件/ JPQLquery指定獲取模式來處理第一種情況。這會將所有內容加載到一個SQL查詢中,但是您仍然可以加載問題的開銷:加載問題可能不是問題,但對於大型數據集,如果只需要計數,開銷可能相當大。

對於第二種情況,您有兩個選項。第一個,Hibernate特定的不可移植的,是利用Hibernate的@Formula註解。

Calculated property with JPA/Hibernate

class Quiz{ 
    @Formula("select count(*) from question where quiz_id = id") 
    int numberOfQuestions; 
} 

,這將給你的問題的數量,而不整個集合加載到內存中。

第二種,非Hibernate特定的便攜式解決方案是創建一個視圖vw_quiz_summary_data,它具有相同的信息。然後,您可以將其映射爲普通實體,並將其作爲一對一關係或@SecondaryTable鏈接到測驗。

+0

謝謝。我以前不知道@Formula。但是我已經找到了很好的解決方案。 @LazyCollection(LazyCollectionOption.EXTRA) 私人列表問題; 休眠不加載所有相關的問題,只有大小。 –

+0

是的,你是對的。這可能是最好的解決方案:忘了那個休眠選項! –

0

看來您需要將FetchType = EAGER添加到Quiz類中的Qustions集合中。

在這種情況下,所有問題(不僅尺寸,而且所有內容)也將在測驗中提取​​到一個查詢中。

class Quiz { 
... 
@OneToMany(fetch = FetchType.EAGER, mappedBy = "quiz") 
    public Set<Question> getStockDailyRecords() { 
     return this.stockDailyRecords; 
    } 
... 
} 

如果您不需要急於獲取的在所有情況下的問題 - 您可以使用您的查詢抓取連接:

@Query(value = "SELECT q FROM Quiz q LEFT JOIN FETCH q.questions", 

在這種情況下,問題都將急切地只爲測驗從這個取查詢。

0

你需要的是JOIN值與您的映射fetch屬性時,會產生只有一個選擇查詢,讓你得到你的集合大小:

@OneToMany(fetch = FetchType.JOIN, mappedBy = "quiz") 
public Set<Question> getQuestions() { 
    ... 
} 

你可以找到更多關於它在Hibernate – fetching strategies examples,這也解釋了所有的獲取策略,其生成的查詢和它們之間的差異,你會看到:

隨着fetch=」join」 or @Fetch(FetchMode.JOIN) Hibernate只生成一條select語句,它在初始化Stock時檢索其所有相關集合。

3

如果你是開放的使用Hibernate特有的註解,你可以做到以下幾點:

class Quiz { 
    @LazyCollection(LazyCollectionOption.EXTRA) 
    @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "quiz", orphanRemoval = true) 
    private Set<Question> questions; 
} 

注意使用@LazyCollection(LazyCollectionOption.EXTRA)

現在,如果你這樣做了quizRepsitory.findOne(...).getQuestions().size(),Hibernate將激發查詢SELECT COUNT(...) FROM question WHERE quiz_id=?。但是,如果你做for(Question question : quizRepsitory.findOne(...).getQuestions()) { ... },Hibernate將激發一個不同的查詢:SELECT * FROM question WHERE quiz_id=?。此外,如果quiz.questions已經加載,則COUNT查詢不會再次被觸發。保存你必須映射QuizQuestion兩次,一次爲實際收集和再次爲計數。