2012-09-10 13 views
5

próbuję wymyślić rozwiązanie następującego problemu z wykorzystaniem MyBatis 3.0.6:Zagnieżdżone foreach w MyBatis 3 dla parametru HashMap

muszę zbudować dynamiczny SELECT na podstawie szeregu parametrów, jeden z tego jest typu HashMap<String, List<String>>. Wyzwaniem jest dowiedzieć się, jak zrobić MyBatis iteracyjne nad wszystkimi kluczami w zewnętrznej pętli foreach, jak również iterować nad elementami listy wartości w wewnętrznej pętli.

Aby zilustrować, załóżmy, że mój hash mapa parametr zwany filtr zawiera Zjednoczone (wykazy kodów państwowych, każda lista jest wartością) od kraju (kod kraju jako klucz) tak:

'US' -> {'CO','NY','MI','AZ'}; 
'CA' -> {'ON','BC','QC'} 

muszę mój dynamiczny SQL, aby wyglądać następująco (w rażąco uproszczonej formie):

SELECT * 
FROM Table1 
WHERE ... some static criteria goes here... 
     AND RowId IN (SELECT RowId FROM Table2 WHERE Country = 'US' AND State IN ('CO','NY','MI','AZ') 
     AND RowId IN (SELECT RowId FROM Table2 WHERE Country = 'CA' AND State IN ('ON','BC,'QC') 

bym sobie wyobrazić moje odwzorowujący XML powinien wyglądać mniej więcej tak:

<select id="getData" resultType="QueryResult"> 
SELECT * 
FROM Table1 
WHERE ... some static criteria goes here... 
    <if test="filter != null"> 
     <foreach item="country" index="i" collection="filter" separator="AND"> 
      RowId IN (SELECT RowId 
         FROM Table2 
         WHERE Country = #{country} AND State IN 
      <foreach item="state" index="j" collection="country.states" separator="," open="(" close=")"> 
       #{state} 
      </foreach> 
     </foreach> 
    </if> 
</select> 

Więc pytanie brzmi, jaka jest właściwa składnia uzyskać country.states do iteracyjnego w zagnieżdżonej foreach pętli?


UPDATE

Po pewnym majsterkowania nie mogłem dostać MyBatis grać ładnie z podejściem HashMap oparte, więc skończyło się na dodanie nowej klasy, która mapuje wiele wartości do wartości nadrzędnej, następnie przekazanie listy takich obiektów do MyBatis. Na przykładzie krajach/stanach powyżej, klasa wygląda tak:

public class Filter { 
    private String country; 
    private ArrayList<String> states; 

    // ... public get accessors here ... 
} 

Metoda DAO:

public void QueryResult[] getResults(@Param("criteria") List<Filter> criteria) ... 

I odwzorowanie MyBatis:

<select id="getData" resultType="QueryResult"> 
SELECT * 
FROM Table1 
WHERE ... some static criteria goes here... 
    <if test="criteria!= null"> 
     <foreach item="filter" index="i" collection="criteria" separator="AND" open="AND"> 
      RowId IN (SELECT RowId 
         FROM Table2 
         WHERE Country = #{filter.country} AND State IN 
      <foreach item="state" index="j" collection="filter.states" separator="," open="(" close=")"> 
       #{state} 
      </foreach> 
     </foreach> 
    </if> 
</select> 

działa jak czar.

Odpowiedz

3

Właściwie możesz użyć wartości kraju, aby wyszukać ją na mapie filtra i sprawić, by działała tak jak początkowo. W drugiej pętli twoja kolekcja będzie zdefiniowana jako filter.get(country) i powinna być dobra. Jest to oczywiście ważne, ponieważ poprawnie interpretuję twoje pytanie.

1

Miałem coś do wstawienia jako mapę, w której każdy klawisz mapy jest mapowany do listy. Napisałem zapytanie w ten sposób.

INSERT INTO TB_TEST (group_id, student_id) VALUES 
<foreach collection="idMap.entrySet()" item="element" index="index" separator=","> 
     <foreach collection="element.value" item="item" separator="," > 
      (#{element.key} #{item})  
     </foreach> 
    </foreach> 
+0

THIS! naprawił to dla mnie. Dzięki! – 98percentmonkey

0

Na razie mogę to zrobić.

<foreach collection="myMap" index="key" item="value"> 
    <foreach collection="value" item="element"> 
    ... = #{key} ... 
    ... = #{element}) 
    </foreach> 
</foreach>