ResultMap, Collection, and AutoMapping Experience

412 views
Skip to first unread message

Brandon Goodin

unread,
Mar 22, 2013, 10:14:38 AM3/22/13
to mybati...@googlegroups.com
I wanted to pass my experience along with regard to dealing with a join based collection in MyBatis 3. I have been able to get it working. But, it took some experimentation to figure out what I needed to do. I think the docs may need to be improved around this. But, I wanted to confirm that what I am experiencing is expected.

I'll chronicle my path of discovery using the SQL examples from the mybatis docs as a basis.

I used a select statement and an initial resultmap like the following:


<select id="selectBlog" parameterType="int" resultMap="blogResult">
  select
  B.id,
  B.title,
  B.author_id as authorId,
  P.id as post_id,
  P.subject as post_subject,
  P.body as post_body,
  from Blog B
  left outer join Post P on B.id = P.blog_id
  where B.id = #{id}
 </select>

<resultMap id="blogResult" type="Blog">
  <collection property="posts" ofType="Post">
    <id property="id" column="post_id"/>
    <result property="subject" column="post_subject"/>
    <result property="body" column="post_body"/>
  </collection>
</resultMap>
My resultmap was defined as minimalistic as I thought I could get away with. Notice that I did not define an "id" in the resultMap. I simply defined the collection. Inefficiencies aside I thought mybatis would recognize the non-collection columns were identical and create the collections items accordingly  I'm not saying this was a good assumption. It was just where my mind was and nothing that _I saw_ (i know it is there) in the documentation was telling me that I needed to have the id column defined in order for the collections to work properly.

The result of this was that I had a Blog object with none of the fields populated except for the posts. But each empty Blog had only one Post in each of their posts collection.


<resultMap id="blogResult" type="Blog">
  <id property="id" column="id" />
  <collection property="posts" ofType="Post">
    <id property="id" column="post_id"/>
    <result property="subject" column="post_subject"/>
    <result property="body" column="post_body"/>
  </collection>
</resultMap>

Next, I decided to try out adding the id column (duh). This provided me the results that I expected with regard to my collection of posts in each Blog being populated properly. But, my Blog was still empty on everything except the id and the posts.

This struck me as odd because the autoMappingBehavior is documented as being set to PARTIAL. The docs define it in the following way:

Specifies if and how MyBatis should automatically map columns to fields/properties. NONE disables auto-mapping. PARTIAL will only auto-map results with no nested result mappings defined inside. FULL will auto-map result mappings of any complexity (containing nested or otherwise).

PARTIAL will only auto-map results with no nested result mappings defined inside.

Given that I did not have a nested result mapping in my resultmap (unless a collection is considered a nested result map) i thought it would map my Blog results properly without any modification. This was clearly not the case.

I thought perhaps I was going to have to define my full resultMap which would have been a bummer since the actual work i was doing was significantly more than the Blog/Post example.

I noticed that the resultMap had an attribute to set the autoMapping. I read the documentation on this and it states the following:

autoMapping If present, MyBatis will enable or disable the automapping for this ResultMap. This attribute overrides the global autoMappingBehavior. Default: unset.
This attribute overrides the global autoMappingBehavior. 

I assumed this meant that I needed to set the value to NONE, PARTIAL, or FULL. But, in reality this is a boolean setting of true/false.


<resultMap id="blogResult" type="Blog" autoMapping="true">
  <id property="id" column="id" />
  <collection property="posts" ofType="Post">
    <id property="id" column="post_id"/>
    <result property="subject" column="post_subject"/>
    <result property="body" column="post_body"/>
  </collection>
</resultMap>
I finally achieved the expected result I wanted. The Blog properties were properly populated and the collection of Posts were properly populated. If my final result is what is expected, then I think the documentation may need to make a few things more clear.

1) It may be good to emphasize the portion of the documentation that states:

"Again, remember the importance of the id elements here, or read the association section above if you haven't already." 

2) I think it may be wise to update the autoMapping docs to provide what the possible values are and state that "unset"(default behavior) will not auto map undefined columns in the resultMap.
autoMapping If present, MyBatis will enable (true) or disable (false) the automapping for this ResultMap. This attribute overrides the global autoMappingBehavior. Default: unset (same as false).
Thoughts? Insights?

Brandon

Eduardo Macarron

unread,
Mar 22, 2013, 12:33:38 PM3/22/13
to mybati...@googlegroups.com
Hi Brandon,

All your assumptions are right. That is exactly how it works and yes, seems the doc in unclear with this regard.

The collection is fact a nested resultmap :) When an association of a collection without a select is read, then the parent resultmap will be handled by the "join processor" instead of the normal one. I does not matter if there is a resultmap id or if there is an "in-line" resultmap. I do agree that we need a definition of "nested resultmap" somewhere in the doc bause it is not evident what is a nested resultmap and what is not.

The problem you had when you did not add the id was not because you need an id but because you need at least one result. MyBatis tries to store the blogs in a map so it can identify it as duplicated when it appears in the nexts rows. I am not familiar with IB2 code but I suppose it works in the same way so you probably already know the internals.

The problem is that there is no data at all, so no blog can be stored and the code just messes up and returns wrong results :)

Regarding the autoMapping, once you are in a resultmap there is no point in specifiying PARTIAL, FULL... you just need to tell MB if you want it to be automapped or not but sure, once again, this is not obvious and the doc should tell that valid values are true/false.




Iwao AVE!

unread,
Mar 22, 2013, 12:34:10 PM3/22/13
to mybatis-user
Hi Brandon,

Thank you for the suggestion.

1) +1

2) Actually, a resultMap that contains a collection or an association is considered as a 'nested resultMap' and that's why the auto mapping did not work in your second try (not because autoMapping is 'unset').

I guess the explanation for the PARTIAL should be improved.
How about this?

PARTIAL: auto mapping is performed only when the resultMap contains no collection or association element.

Any correction (grammar or technical) is welcome.

Regards,
Iwao

eugen.be...@gmail.com

unread,
Mar 25, 2013, 4:34:25 AM3/25/13
to mybati...@googlegroups.com
Thanks Brandon, Eduardo and Iwao,

I ran into the same problem but with an association. Now after reading your description I could solve it properly.
Reply all
Reply to author
Forward
0 new messages