MyBatis version

3.5.5

Database vendor and version

Oracle 12C

Test case or example project

I've a test case which is working fine on Mybatis version 3.5.4 Here is my XML mapper

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.mycom.query.test">
    <resultMap id="headerResultMap" type="com.mycom.query.test.TestHeader">
        <constructor>
            <idArg column="H_ID" javaType="_int" name="id"/>
        </constructor>
        <result property="field1" column="H_FIELD1"/>
        <result property="field2" column="H_FIELD2"/>
        <result property="field3" column="H_FIELD3"/>
    </resultMap>

    <resultMap id="detailResultMap" type="com.mycom.query.test.TestDetail">
        <constructor>
            <idArg column="D_ID" javaType="_int" name="id"/>
            <idArg column="D_SEQ" javaType="_int" name="seq"/>
        </constructor>
        <result property="field1" column="D_FIELD1"/>
        <result property="field2" column="D_FIELD2"/>
        <result property="field3" column="D_FIELD3"/>
    </resultMap>

    <resultMap id="testResultMap" type="com.mycom.query.test.TestOrder">
        <constructor>
            <idArg resultMap="headerResultMap" javaType="com.mycom.query.test.TestHeader"/>
        </constructor>
        <collection property="details" ofType="com.mycom.query.test.TestDetail" resultMap="detailResultMap"/>
    </resultMap>

    <select id="find" resultMap="testResultMap">
        SELECT
            *
        FROM (
            SELECT
                1 AS H_ID,
                'H_FIELD1' AS H_FIELD1,
                'H_FIELD2' AS H_FIELD2,
                'H_FIELD3' AS H_FIELD3
            FROM
                DUAL
        ) H
        LEFT JOIN (
            SELECT
                1 AS D_ID,
                1 AS D_SEQ,
                'D_FIELD1' AS D_FIELD1,
                'D_FIELD2' AS D_FIELD2,
                'D_FIELD3' AS D_FIELD3
            FROM
                DUAL
            UNION ALL
            SELECT
                1 AS D_ID,
                2 AS D_SEQ,
                'D_FIELD4' AS D_FIELD1,
                'D_FIELD5' AS D_FIELD2,
                'D_FIELD6' AS D_FIELD3
            FROM
                DUAL
            UNION ALL
            SELECT
                1 AS D_ID,
                3 AS D_SEQ,
                'D_FIELD7' AS D_FIELD1,
                'D_FIELD8' AS D_FIELD2,
                'D_FIELD9' AS D_FIELD3
            FROM
                DUAL
        ) D ON H.H_ID=D.D_ID
    </select>
</mapper>

The result will produce one to many rows and map to my model

import java.util.List;

public class TestOrder {

    private final TestHeader header;

    private List<TestDetail> details;

    public TestOrder(TestHeader header) {
        this.header = header;
    }

    public TestHeader getHeader() {
        return header;
    }

    public List<TestDetail> getDetails() {
        return details;
    }

    public void setDetails(List<TestDetail> details) {
        this.details = details;
    }

    @Override
    public String toString() {
        return getClass().getName() + "[header=" + header + ", details=" + details + ']';
    }
}

Steps to reproduce

Call using selectOne method, and I'm expect it will return 1 single object which is TestOrder. However, Mybatis 3.5.5 failed with message Expected one result (or null) to be returned by selectOne(), but found: 3

Expected result

1 object with 3 details inside

Actual result

Failed

Comment From: harawata

Hello @vlcheong ,

Could you create and share an executable project like these on GitHub?

Comment From: vlcheong

@harawata Here is my test

Comment From: harawata

Thank you for the repro, @vlcheong . The cause of your issue was a change made related to #1848 .

Previously, MyBatis used nested result mapping like <constructor /> to identify the parent object, however, the logic was complex and was not always valid, so we removed it from the mapping process.

It is unfortunate that the change broke your solution, but you basically need to add <id /> to the testResultMap with MyBatis ≥3.5.5.

<resultMap id="testResultMap" type="com.mapper.model.TestOrder">
  <constructor>
    <idArg resultMap="headerResultMap" javaType="com.mapper.model.TestHeader"/>
  </constructor>
  <id column="H_ID" /><!-- added -->
  <collection property="details" ofType="com.mapper.model.TestDetail" resultMap="detailResultMap"/>
</resultMap>

Comment From: vlcheong

@harawata Thanks for the solution. Will this solution works for composite key ?

Comment From: harawata

It should. There can be multiple <id />s in a result map.

Comment From: vlcheong

Issue solved after adding id tag