mybatis-3 icon indicating copy to clipboard operation
mybatis-3 copied to clipboard

Constructor Args Map Incorrect Columns When Using resultMap property

Open nileflowers opened this issue 7 years ago • 4 comments

MyBatis version

3.4.4 tested with 3.4.2, 3.4.0 as well.

Database vendor and version

H2 version 1.4.193 (although this issue is not related to H2 per se)

Test case or example project

Please see self-contained maven project with the full regression test (5.8KB) regression0.zip

Steps to reproduce

Create a constructor result map <arg/> or <idArg/> that references another POJO that has similarly named property to the one being mapped. See below (or attached regression test for full mapping):

<resultMap id="ParentResultMap" type="dto.Parent">
    <constructor>
        <!-- this property is named 'id' in the Parent class -->
        <arg column="p_id" javaType="java.lang.String" jdbcType="VARCHAR"/>
        <!-- ... more ... -->
    </constructor>
</resultMap>

<resultMap id="ChildResultMap" type="dto.Child">
    <constructor>
        <!-- this property is named 'id' in the Child class -->
       <idArg column="id" javaType="java.lang.String" jdbcType="VARCHAR"/>
        <!-- ... more ...-->
        <arg javaType="dto.Parent" resultMap="ParentResultMap"/>
    </constructor>
</resultMap>
public class Parent {
    private final String id;
    // ...
    public Parent(String id /*, ...*/) {
        this.id = id;
        //....
    }
   //...
}

public class Child {

    private final String id;
    //...
    private final Parent parent;

    public Child(String id, /*, ... */ Parent parent) {
        this.id = id;
        //...
        this.parent = parent;
    }
   //...
}

Expected result

Column p_id should map to Parent's constructor first argument. For the row returned below

ID, NAME, P_ID, P_NAME
10, Child Name, 11, Parent Name

Parent's id should be 11

Actual result

Column id is instead mapped to the Parent's constructor first argument. For the row shown above, Parent's id is instead 10

Workarounds

  • Rename properties so that names don't match between classes, or
  • Convert immutable classes to mutable with default constructor, getters and setters, then switch mapping to non-constructor mapping using <result/>.

nileflowers avatar May 06 '17 15:05 nileflowers

This has to do with how mybatis allows both constructor mapping and post constructor setter mapping Which is useful for example for collections which constructor mapping does not currently support unless you use a sub select.

I'm trying to see how to 'disable' this behavior without breaking the post constructor property setting but for now you can also set the automappingbehavior (assuming that doesn't break other parts of your app)

configuration.setAutoMappingBehavior(AutoMappingBehavior.NONE);

h3adache avatar May 08 '17 19:05 h3adache

Another workaround is autoMapping="false" on resultMap element as follow:

<resultMap id="ParentResultMap" type="dto.Parent" autoMapping="false">
    <!-- ... -->
</resultMap>

kazuki43zoo avatar May 08 '17 22:05 kazuki43zoo

Ah yea thanks for the reminder @kazuki43zoo

h3adache avatar May 09 '17 01:05 h3adache

automapping doesn't exist on the annotations yet. The solution propose by @kazuki43zoo only works for xml mapping or globally atm.

h3adache avatar Nov 21 '17 00:11 h3adache