其實(shí)這個(gè)問(wèn)題在Hibernate in Action中已經(jīng)有很多種解決辦法了。但我覺(jué)得其中最好的辦法是用Criteria的FetchMode來(lái)解決,但是Hibernate in Action中寫(xiě)的很不詳細(xì)。我昨晚試了好長(zhǎng)時(shí)間來(lái)的到答案。下面總結(jié)一下。 需求這樣的,我有四張表(one,two,three,four)從one一直外鍵關(guān)聯(lián)到four。結(jié)構(gòu)如下 ![]() 現(xiàn)在在Session中得到One,并從One里一直取到Four里的內(nèi)容。如果簡(jiǎn)單的用Session.get來(lái)實(shí)現(xiàn)是這樣的。 One one = (One)session.get(One.class,new Integer(1)); 這樣我在Session關(guān)閉后返回的One里是從One到Four的信息都有的。Iterator iterone = one.getTwos().iterator(); while(iterone.hasNext()){ Two two = (Two) iterone.next(); Iterator itertwo = two.getThrees().iterator(); while(itertwo.hasNext()){ Three three = (Three) itertwo.next(); three.getFours().size(); } } 然而這樣做所導(dǎo)致的結(jié)果是生成大量的SQL查詢,這是一個(gè)典型的n+1 Selects問(wèn)題。如果系統(tǒng)結(jié)構(gòu)層次多,符合條件的記錄多,那么Hibernate為你生成的SQL查詢將是難以接受的。 對(duì)于這個(gè)例子生成的SQL是這樣的 Hibernate: select one0_.c_one_id as c1_0_, one0_.c_one_text as c2_3_0_ from One one0_ where one0_.c_one_id=? Hibernate: select twos0_.c_one_id as c2_1_, twos0_.c_two_id as c1_1_, twos0_.c_two_id as c1_0_, twos0_.c_one_id as c2_2_0_, twos0_.c_two_text as c3_2_0_ from Two twos0_ where twos0_.c_one_id=? Hibernate: select threes0_.c_two_id as c2_1_, threes0_.c_three_id as c1_1_, threes0_.c_three_id as c1_0_, threes0_.c_two_id as c2_1_0_, threes0_.c_three_text as c3_1_0_ from Three threes0_ where threes0_.c_two_id=? Hibernate: select fours0_.c_three_id as c2_1_, fours0_.c_four_id as c1_1_, fours0_.c_four_id as c1_0_, fours0_.c_three_id as c2_0_0_, fours0_.c_four_text as c3_0_0_ from Four fours0_ where fours0_.c_three_id=? Hibernate: select fours0_.c_three_id as c2_1_, fours0_.c_four_id as c1_1_, fours0_.c_four_id as c1_0_, fours0_.c_three_id as c2_0_0_, fours0_.c_four_text as c3_0_0_ from Four fours0_ where fours0_.c_three_id=? Hibernate: select threes0_.c_two_id as c2_1_, threes0_.c_three_id as c1_1_, threes0_.c_three_id as c1_0_, threes0_.c_two_id as c2_1_0_, threes0_.c_three_text as c3_1_0_ from Three threes0_ where threes0_.c_two_id=? Hibernate: select fours0_.c_three_id as c2_1_, fours0_.c_four_id as c1_1_, fours0_.c_four_id as c1_0_, fours0_.c_three_id as c2_0_0_, fours0_.c_four_text as c3_0_0_ from Four fours0_ where fours0_.c_three_id=? Hibernate: select fours0_.c_three_id as c2_1_, fours0_.c_four_id as c1_1_, fours0_.c_four_id as c1_0_, fours0_.c_three_id as c2_0_0_, fours0_.c_four_text as c3_0_0_ from Four fours0_ where fours0_.c_three_id=? 對(duì)于這樣的問(wèn)題,在沒(méi)有Hibernate以前我們一般都用jdbc來(lái)做,那樣的話我們其實(shí)用一個(gè)進(jìn)行3次join的sql語(yǔ)句就可以實(shí)現(xiàn),但是這樣解決也有問(wèn)題,就是返回的ResultSet中的數(shù)據(jù)非常多,而且雜亂,其實(shí)是從one到four平行排列的。對(duì)于這樣的結(jié)果集我們要把它手動(dòng)影射曾對(duì)象結(jié)構(gòu)也是一個(gè)很復(fù)雜的操作。 幸好Hibernate3可以為我們做這些事情(我再一次被Hibernate的強(qiáng)大所震撼)。 上面的實(shí)現(xiàn)可以用Criteria來(lái)實(shí)現(xiàn): session = sessionFactory.openSession(); Criteria criteria = session.createCriteria(One.class); criteria.add(Expression.eq("COneId",new Integer(1))); one = (One)criteria.setFetchMode("twos",FetchMode.JOIN).setFetchMode("twos.threes",FetchMode.JOIN).setFetchMode("twos.threes.fours",FetchMode.JOIN).uniqueResult(); session.close(); 這里的重點(diǎn)是這句話criteria.setFetchMode("twos",FetchMode.JOIN).setFetchMode("twos.threes",FetchMode.JOIN).setFetchMode("twos.threes.fours",FetchMode.JOIN).uniqueResult(); |
聯(lián)系客服