DaveyDaveDave DaveyDaveDave - 2 months ago 7
Java Question

If I define an <association> in a <resultMap> in MyBatis, do I have to define all fields even if the properties match the column names?

I'm trying out MyBatis in a project and so far have been fairly impressed. I'm using the Spring Boot starter, and ideally would like to have as much config as possible in annotations.

Everything was going well until I tried to implement a 'has-a' join in my mapper. I have a customer entity which has an address:

Customer (id, name, email, ...)
Address (id, customerId, street, city, ...)


Perhaps I'm wrong (I hope so), but it seems to be impossible to map this using annotations (if I want to avoid the N+1 issue, which I do), so I've reluctantly created a customerMapper.xml file, which contains:

<mapper namespace="foo.domain.mapper.CustomerMapper">
<resultMap id="customer" type="foo.domain.Customer">
<id property="id" column="customerId"/>
<association property="address" resultMap="address"/>
</resultMap>

<resultMap id="address" type="foo.domain.Address">
<id property="id" column="addressId"/>
</resultMap>
</mapper>


and in my mapper I have:

@Select("SELECT * FROM Customer cus LEFT OUTER JOIN Address adr ON adr.customerId = cus.customerId")
@ResultMap("customer")
List<Customer> findAll();


When I call
findAll()
, however, I find that only the
id
fields of
customer
and
address
are populated, despite the fact that the property names match the column names for both Customer and Address, so I would expect MyBatis to auto-map them.

If I take out the
<association>
, I get a fully populated
customer
. Similarly, if I start adding in
<result>
elements in each
<resultMap>
the fields I add elements for are populated correctly.

So - my question is - is it correct that if I specify an
<association>
, the rest of my fields will not be auto-mapped, so I have to explicitly specify every field in the XML? If so, and given that the data structure I have (which cannot be changed) requires joins for most queries, I think I'm going to end up writing more code if I use MyBatis than plain JDBC!

Answer Source

I think I've found the answer to my own question here.

There are three auto-mapping levels:

NONE - disables auto-mapping. Only manually mapped properties will be set.
PARTIAL - will auto-map results except those that have nested result mappings defined inside (joins).
FULL - auto-maps everything.

The default value is PARTIAL, and it is so for a reason. When FULL is used auto-mapping will be performed when processing join results and joins retrieve data of several different entities in the same row hence this may result in undesired mappings.

So by default, in my case, auto-mapping does not happen. I need to decide whether to switch it on or not.