Ich versuche, eine Lösung für das folgende Problem mit MyBatis 3.0.6 herauszufinden:
Ich muss eine dynamische Select-Anweisung erstellen, die auf einer Reihe von Parametern basiert, von denen einer vom Typ HashMap<String, List<String>>
. Die Herausforderung besteht darin, herauszufinden, wie man MyBatis dazu bringt, über alle Schlüssel in einem äußeren Verzeichnis zu iterieren. foreach Schleife sowie über die Elemente der Werteliste in der inneren Schleife zu iterieren.
Zur Veranschaulichung: Angenommen, mein Hash-Map-Parameter heißt Filter enthält Staaten (Listen von Staatencodes, jede Liste ist der Wert) pro Land (Ländercode als Schlüssel) wie folgt:
'US' -> {'CO','NY','MI','AZ'};
'CA' -> {'ON','BC','QC'}
Mein dynamisches SQL muss wie folgt aussehen (in stark vereinfachter Form):
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')
Ich könnte mir vorstellen, dass mein Mapper-XML etwa so aussehen sollte:
<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>
Die Frage ist also, wie lautet die richtige Syntax, um die Länder.Staaten für die Iteration in der verschachtelten foreach Schleife?
UPDATE
Nach einigem Herumprobieren konnte ich MyBatis nicht dazu bringen, mit dem HashMap-basierten Ansatz mitzuspielen, also fügte ich schließlich eine neue Klasse hinzu, die mehrere Werte auf ihren übergeordneten Wert abbildet, und übergab dann eine Liste solcher Objekte an MyBatis. Anhand des obigen Länder/Staaten-Beispiels sieht die Klasse wie folgt aus:
public class Filter {
private String country;
private ArrayList<String> states;
// ... public get accessors here ...
}
Die DAO-Methode:
public void QueryResult[] getResults( @Param("criteria") List<Filter> criteria) ...
Und die MyBatis-Zuordnung:
<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>
Funktioniert wie ein Zauber.