假设我们有MyBatis 3.3.0和MyBatis-Spring 1.2.3以及一个简单的选择查询......
<select id="testSelect" parameterType="map" resultType="Integer">
select 1 from dual where
<foreach collection="properties" index="index" item="item" separator=" and ">
1 = #{id} AND 'a' = #{item.key,jdbcType=VARCHAR} AND 'b' = #{item.value,jdbcType=VARCHAR}
</foreach>
</select>
(如果给定的id是1,并且集合中给出的所有关键属性都是&#34; a&#34;以及所有值&#34; b&#34;)
...这是一个简单的TestMapper
接口方法......
Integer testSelect(Map<String, Object> arguments);
......我们用这种测试方法测试它......
@Test
public void test_for_bug() {
final Map<String, Object> parameters = new HashMap<>();
parameters.put("id", 1);
final Map<String, String> entries = new HashMap<>();
entries.put("a", "b");
parameters.put("properties", entries.entrySet());
final Integer result = this.testMapper.testSelect(parameters);
assertThat(result).isEqualTo(1);
}
...我们会收到以下错误....
对于属性的参数映射,类型处理程序为null &#39; __ frch_item_0.value&#39 ;.它没有指定和/或不能 找到指定的javaType / jdbcType组合。
原因似乎是对item.value
的调用导致调用String本身的value
属性。不幸的是,我不知道为什么。
将entries.entrySet()
替换为Collection
个自定义Entry
个对象(key
和value
属性)可以正常工作。同样奇怪:这似乎只发生在<collection>
内,直接将Map.Entry
作为参数,例如......
<select id="testSelect" parameterType="map" resultType="Integer">
select 1 from dual where 'b' = #{entry.value,jdbcType=VARCHAR}
</select>
...和...
@Test
public void test_for_bug() {
final Map<String, String> entries = new HashMap<>();
entries.put("a", "b");
final Map<String, Object> parameters = new HashMap<>();
parameters.put("entry", entries.entrySet().iterator().next());
final Integer result = this.testMapper.testSelect(parameters);
assertThat(result).isEqualTo(1);
}
...作品。
有谁知道Map.EntrySet的问题是什么?有机会以某种方式修复它吗?当然,创建一个变通方法很容易,但不应该需要它。
答案 0 :(得分:2)
似乎正确处理此问题的方法(文档更新已提交)如下(因为开发人员在几个版本之前做了一些更改):
<select id="testSelect" parameterType="map" resultType="Integer">
select 1 from dual where
<foreach collection="properties" index="index" item="item" separator=" and ">
1 = #{id} AND 'a' = #{index,jdbcType=VARCHAR} AND 'b' = #{item,jdbcType=VARCHAR}
</foreach>
</select>
原因是,<foreach>
/ Iterables
和Arrays
(以及Maps
个对象Iteratable<Map.Entry>
的行为略有不同:
Iterable
或Array
,index
是当前迭代的编号,item
是在此迭代中从Iterable中检索的元素。Map
(或Iterable<Map.Entry>
)index
,当前条目的密钥和项目是当前条目的value
这解释了为什么item.value
导致Map<String, String>
实际导致String.value
value
已经是String
的原因char array
为私有value
}成员名为String.value
,因此MyBatis正在尝试访问char array
- 并失败,因为ret = objhttp.Open("POST", sURL, False)
objhttp.setRequestHeader "Content-Type", "application/json"
objhttp.setRequestHeader "Accept", "application/json"
'V3 API uses HTTP Basic Authorisation inside an https: wrapper.
'The standard windows method does not seem to work however the
'following hack does.
'In summary the user name and APIkey are seperated with a Colon: and
'base 64 encoded and added to a Http RequestHeader
objhttp.setRequestHeader "Authorization", "Basic " & Base64Encode(APIUser & ":" & ApiKey)
objhttp.send (sJson)
不是映射类型。)
答案 1 :(得分:0)
您只需传递参数贴图而不是map.entrySet(),就像这样
parameters.put("properties", entries);
并像那样打电话给你的mybatis
<select id="testSelect" parameterType="map" resultType="Integer">
select 1 from dual where
<foreach collection="properties.entrySet()" index="index" item="item" separator=" and ">
1 = #{id} AND 'a' = #{item.key,jdbcType=VARCHAR} AND 'b' = #{item.value,jdbcType=VARCHAR}
</foreach>
</select>