在 MyBatis 3 中为 HashMap 参数嵌套 foreach

Posted

技术标签:

【中文标题】在 MyBatis 3 中为 HashMap 参数嵌套 foreach【英文标题】:Nested foreach in MyBatis 3 for a HashMap parameter 【发布时间】:2012-09-10 19:25:42 【问题描述】:

我正在尝试使用 MyBatis 3.0.6 解决以下问题:

我需要基于一系列参数构建一个动态选择语句,其中一个参数是HashMap<String, List<String>> 类型。挑战在于弄清楚如何让 MyBatis 遍历外部 foreach 循环中的所有键,以及遍历内部循环中值列表的元素。

为了说明,假设我的名为 filter 的哈希映射参数包含每个国家(国家代码作为键)的州(州代码列表,每个列表都是值)像这样:

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

我需要我的动态 SQL 看起来像这样(以非常简化的形式):

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')

我想我的映射器 XML 应该是这样的:

<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>

所以问题是,让 country.states 在嵌套的 foreach 循环中迭代的正确语法是什么?


更新

经过一些修改后,我无法让 MyBatis 很好地使用基于 HashMap 的方法,所以我最终添加了一个新类,它将多个值映射到它们的父值,然后将这些对象的列表传递给 MyBatis。使用上面的国家/州示例,该类如下所示:

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

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

DAO 方法:

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

还有 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>

像魅力一样工作。

【问题讨论】:

【参考方案1】:

实际上,您可以使用国家/地区值在过滤器地图中查找它,并使其像您最初拥有的那样工作。在第二个循环中,您的集合将被定义为filter.get(country),这应该很好。这当然是考虑到我正确地解释了您的问题。

【讨论】:

【参考方案2】:

我有一些东西要作为地图插入,其中每个地图键都映射到一个列表。 我是这样写查询的。

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>

【讨论】:

这个!为我修好了。谢谢!【参考方案3】:

到目前为止,我可以做到这一点。

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

【讨论】:

以上是关于在 MyBatis 3 中为 HashMap 参数嵌套 foreach的主要内容,如果未能解决你的问题,请参考以下文章

MyBatis3——输出参数ResultType动语态sql

测试Mybatis批量查询和使用HashMap查询效率

Mybatis 多个参数传入的多种方法

MyBatis在表名作为参数时遇到的问题

mybatis中的#{}和${}

mybatis中怎么传参数可以提高查询效率