Map.Entry和Map.entrySet()的集合上的MyBatis错误 [英] MyBatis Error on Collection of Map.Entry and Map.entrySet()

查看:1626
本文介绍了Map.Entry和Map.entrySet()的集合上的MyBatis错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设我们有MyBatis 3.3.0和MyBatis-Spring 1.2.3和一个简单的选择查询...

  ; select id =testSelectparameterType =mapresultType =Integer> 
从double选择1,其中
< foreach collection =propertiesindex =indexitem =itemseparator =and>
1 =#{id} AND'a'=#{item.key,jdbcType = VARCHAR} AND'b'=#{item.value,jdbcType = VARCHAR}
< / foreach>
< / select>

(应该简单的返回1,如果给定的id为1,该集合是a和所有值b)



...这使得一个简单的 TestMapper 接口方法...

 整数testSelect(Map< String,Object>参数); 

...我们使用此测试方法测试...

  @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整数结果= this.testMapper.testSelect(parameters);

assertThat(result).isEqualTo(1);

}

...我们会收到以下错误...


属性
'__frch_item_0.value'的参数映射类型处理程序为空。没有指定和/或不能为指定的javaType / jdbcType组合找到


这似乎是调用 item.value 导致String本身的属性的调用。不幸的是,我不知道为什么。



entries.entrySet()替换为集合定制条目对象(含属性) 工作正常。也奇怪的是:这只是在一个< collection> 中发生,直接作为一个参数给出一个 Map.Entry ,如...

 < select id =testSelectparameterType =mapresultType =Integer> 
从double选择1,其中'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整数结果= this.testMapper.testSelect(parameters);

assertThat(result).isEqualTo(1);

}

...工作。

$ b $有没有人知道Map.EntrySet的问题在这里?有机会得到它固定不知何故?当然,创建一个解决方法很简单,但是不应该需要它。

解决方案

看起来正确的方法来处理这个(已经提交的文档更新)如下(由于开发人员在几个版本之前进行了一些更改):

 < select id =testSelectparameterType =mapresultType =Integer> 
从double选择1,其中
< foreach collection =propertiesindex =indexitem =itemseparator =and>
1 =#{id} AND'a'=#{index,jdbcType = VARCHAR} AND'b'=#{item,jdbcType = VARCHAR}
< / foreach>
< / select>

原因是,< foreach> Iterables / 数组地图(和 Iteratable< Map.Entry> 对象):




  • code> Iterable 或 Array index 是当前迭代的编号和项目是在此迭代中从Iterable检索的元素。

  • 对于 Map (或 Iterable< Map.Entry> index 是当前条目的关键字,项目是当前条目的价值



这就解释了为什么 item.value for Map< String,String> 实际上导致 String.value value 已经是一个 String - 它有一个私人的 char数组称为,所以MyBatis试图访问 String.value 并且失败,因为 char数组不是映射类型)。


assuming we have MyBatis 3.3.0 and MyBatis-Spring 1.2.3 and a simple select query...

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

(should simple return 1, if the id given is 1 and all key properties given in the collection are "a" and all values "b")

...which makes a simple TestMapper interface method...

Integer testSelect(Map<String, Object> arguments);

...and we test it with this test method...

@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);

}

...we will get the following error....

Type handler was null on parameter mapping for property '__frch_item_0.value'. It was either not specified and/or could not be found for the javaType / jdbcType combination specified.

The reason for that seems to be that the call to item.value results in a call of the value property of the String itself. Unfortunately, I have no clue, why.

Replacing the entries.entrySet() with a Collection of custom Entry objects (with key and value property) works fine. Also strange: This only seems to happen inside a <collection>, giving a Map.Entry directly as a parameter, like...

<select id="testSelect" parameterType="map" resultType="Integer">
    select 1 from dual where 'b' = #{entry.value,jdbcType=VARCHAR}
</select>

...and...

@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);

}

...works.

Has anyone an idea what the problem with Map.EntrySet is here? Any chance to get it fixed somehow? Of course creating a workaround is easy enough, but imho it should not be needed.

解决方案

Seems that the correct way to handle this (documentation update already submitted) is the following (since the developers made some changes a few versions ago):

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

The reason is, that <foreach> behaves a little bit different for Iterables/Arrays and Maps (and Iteratable<Map.Entry> Objects):

  • For an Iterable or Array, index is the number of the current iteration and item is the element retrieved from the Iterable in this iteration.
  • For a Map (or Iterable<Map.Entry>) index is the current entry's key and item is the current entry's value

This explains why item.value for a Map<String, String> leads actually to String.value (the value is already a String - which has a private char array member called value, so MyBatis is trying to access String.value - and fails, because a char array is not a mapped type).

这篇关于Map.Entry和Map.entrySet()的集合上的MyBatis错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆