2016-03-01 3 views
0

предполагая, что мы имеем MyBatis 3.3.0 и MyBatis-Spring 1.2.3 и простой запрос на выборку ...MyBatis Ошибка на Сборнике Map.Entry и Map.entrySet()

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

(должны просто Возвращает 1, если идентификатор дается в 1 и все ключевые свойства, приведенные в коллекции «а» и все значения «б»)

... что делает простой метод 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); 

} 

... мы получим следующую ошибку ....

Тип обработчик был нулевым картографирование параметров для недвижимости '__frch_item_0.value'. Он не был указан и/или не мог найти для указанной комбинации javaType/jdbcType.

Причина этого, кажется, что призыв к item.value результатам в вызове 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

Почему вы используете parameters.put ("properties", entries.entrySet())? –

+0

В этом случае, поскольку это простой способ дать набор ключевых пар значений из карты ... Другими словами: почему бы и нет? Это либо это, либо преобразование карты вручную в набор объектов с атрибутами ключа/значения ... (И технически, я не знаю, поскольку я не писал оригинальный код, я просто нашел там ошибку). –

ответ

1

Кажется, что правильный способ справиться с этим (обновление документации уже поданную) следующий (так как разработчики внесли некоторые изменения несколько версий назад):

<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 и MapsIteratable<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, поэтому MyBatis пытается получить доступ к String.value - и не работает, потому что char array не является отображенным типом).

0

Вы просто передаете карту параметров вместо карты.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> 
+0

Вы на самом деле пытались это сделать? Потому что для меня это ничего не меняет. Такая же проблема: «Обработчик типа был равен нулю при сопоставлении параметров для свойства ...» –

+0

Какова ваша версия mybatis? Это решение не поддерживается с версии 3.2x. Проверьте эту проблему https://github.com/mybatis/mybatis-3/pull/208 –

+0

Пробовал ее с помощью 3.3.1 и мог быть такой же проблемой, правда. –