Skip to content

Unable to use composite key in nested query #725

@ghost

Description

MyBatis version

3.2.5+

Database vendor and version

Oracle 12c

Test case or example project

@Result(
        property="someProperty", 
        column="{param1Name=resultColumnNameForParam1, param2Name=resultColumnNameForParam2}",
        one=@One(select = "foo.MapperClass.mapperMethodName"))

@Select("select * from someTable where column1 = #{param1Name,jdbcType=INTEGER} and column2 = #{param2Name,jdbcType=INTEGER}")
int mapperMethodName(@Param("param1Name") int param1Name, @Param("param2Name") int param2Name)

Steps to reproduce

  1. Have a nested query that uses a mapper method taking multiple parameters.
  2. Use a composite key for column like:
    • "{param1Name=resultColumnNameForParam1, param2Name=resultColumnNameForParam2}"
    • or "param1Name=resultColumnNameForParam1, param2Name=resultColumnNameForParam2"

Expected result

Nested query with composite key works successfully.

Actual result

BindException is thrown "org.apache.ibatis.binding.BindingException: Parameter 'param1Name' not found. Available parameters are []"

Cause

This appears to have been caused by the fix for issue #135.

It makes the following change:
parameterType = ParamMap.class; // issue #135

whereas before that was:
parameterType = Map.class;

Map does not throw an error on retrieving a key that doesn't exist, while ParamMap does throw a BindException in this scenario.

This causes DefaultResultSetHandler to fail when it makes a call to prepareCompositeKeyParameter(). It constructs a MetaObject wrapping a ParamMap when it used to wrap a Map. This results in a MapWrapper being created by the MetaObject.

When prepareCompositeKeyParameter then makes a call to MetaObject.getSetterType() which calls MapWrapper.getSetterType(), the BindException is thrown.

In MapWrapper you can see the following code in getSetterType:

      if (map.get(name) != null) {
        return map.get(name).getClass();
      } else {
        return Object.class;
      }

The else can never be reached for a ParamMap because it will never return null, but instead throw a BindException.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions