Skip to content

Can mybatis support mapper xml extend feature? #35

Closed
@akuma

Description

@akuma

For example, I have one common mapper 'CommonUserMapper':

  • CommonUserMapper.java (interface)
  • CommonUserMapper.xml (mapper xml)

Now I want to add some custom methods without changing CommonUserMapper.
So I write a new mapper called CustomUserMapper extends from CommonUserMapper:

  • CustomUserMapper.java (interface)
  • CustomUserMapper.xml (mapper xml)

For this working, I can copy all the codes from the CommonUserMapper.xml to CustomUserMapper.xml.
Of course I can reference some sqls by namespace + ids, but I can't reference the whole select, insert, update, delete...right? So I have to write many duplicate codes.

If the mapper xml can be extended, I think to do this work is more easy.
e.g.

<mapper namespace="demo.CustomUserMapper" extends="demo.CommonUserMapper">

    <!-- Now I don't have to copy other statements used by
         the methods extended from CommonUserMapper.java -->
    <!-- I just define the custom statements -->
    <select id="findByXxx" parameterType="string" resultType="User">
        <!-- findColumn is defined in CommonUserMapper.xml -->
        <include refid="findColumn" />
        where xxx = #{value}
    </select>
    ...
</mapper>

Activity

emacarron

emacarron commented on Apr 30, 2013

@emacarron
Member

Copied from the user mail list:

Current version does not have that option.

Let me try to explain how inheritance works.

interface Parent { 
  @select() 
  annotatedParentMethod(); 
  xmlParentMethod(); 
} 
interface Child extends Parent { 
} 

When loading the Child type MyBatis does two things:

  • Creates a new mapped statement called "Child.annotatedParentMethod"
  • Searches for Child.xml and loads the statemens of the Child namespace

When executing MyBatis gets the id of the statement by concatenating
the name of the mapper and the called method. So if you call
annotatedParentMethod on Child it will execute the statement name
"Child.annotatedParentMethod"

Note that when using annotations there is no need to load the Parent
to use the method annotatedParentMethod. In fact, if the parent is
loaded a new mapped statement called Parent.annotatedParentMethod will
be created. (with the same exact content than
Child.annotatedParentMethod())

Probably we could change the way MyBatis gets the id of the statement:

  • try with self name and method name (Child.xmlParentMethod) (this is
    already being done)
  • If not found, then try with method.getDeclaringClass().getName()
    (Parent.xmlParentMethod)

Unlike with annotated methods, with xml you have to load the Parent
type (or the Parent.xml) so that MyBatis creates the
Parent.xmlParentMethod statement.

akuma

akuma commented on May 1, 2013

@akuma
Author

OK. Thanks for your patiently explanation.

pinootto

pinootto commented on Nov 14, 2013

@pinootto

I am using mybatis version 3.2.3 and I would like to use the mapper extending feature.

My xml code is:

<?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.pino.mappers.AssetMapper" extends="com.pino.mappers.mybatis.AssetMapper">
</mapper>

where com.pino.mappers.mybatis.AssetMapper is generated automatically by mybatis generator.

Eclipse gives me the error: Attribute "extends" must be declared for element type "mapper".

How can I resolve this problem? Is this feature working in mybatis version 3.2.3?

themez

themez commented on May 12, 2014

@themez

This issue seems not completely fixed yet. Here's a case:

I add a configuration option on generator to make it generate Mapper interfaces extends a BaseMapper interface

public interface BaseMapper<T, PK extends Serializable, E> {
    int countByExample(E example);

    int deleteByExample(E example);

    int deleteByPrimaryKey(PK id);

    int insert(T record);

    int insertSelective(T record);

    List<T> selectByExample(E example);

    T selectByPrimaryKey(PK id);

    int updateByExampleSelective(@Param("record") T record, @Param("example") E example);

    int updateByExample(@Param("record") T record, @Param("example") E example);

    int updateByPrimaryKeySelective(T record);

    int updateByPrimaryKey(T record);
}
//generated mapper
interface MyMapper extends BaseMapper{
}
//my custom mapper
interface MyCustomMapper{
  extQuery();
}

It only query statement in MyCustomMapper and BaseMapper, but of course there's no statement in BaseMapper namespace.

P.S.
qq20140512105116

hengchengfei

hengchengfei commented on Dec 4, 2014

@hengchengfei

#Child Dao
package com.self.app.dao;
import com.self.app.dto.ContentDto;

public interface ContentDao extends ContentDtoMapper {
ContentDto getC();
}

#Child Xml

<resultMap id="ResultMap" type="com.self.app.dto.ContentDto" extends="com.self.app.dao.ContentDtoMapper.BaseResultMap" /> 

<select id="getC" resultMap="ResultMap">
    select * from content where id=1
</select>
ilkomiliev

ilkomiliev commented on Oct 6, 2015

@ilkomiliev

As themez pointed out above this issue is not completed - I've added an additional implementation to check the superinterfaces of the mapperInterface and try to get the statement from there, if the current implementation still returns null - what should be the best way to share it?

added a commit that references this issue on Mar 12, 2017

fixes #481 Looks for a matching statement defined in super interfaces…

added a commit that references this issue on Oct 19, 2023

fixes mybatis#481 Looks for a matching statement defined in super int…

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

enhancementImprove a feature or add a new feature

Type

No type

Projects

No projects

Relationships

None yet

    Development

    No branches or pull requests

      Participants

      @akuma@pinootto@themez@emacarron@hengchengfei

      Issue actions

        Can mybatis support mapper xml extend feature? · Issue #35 · mybatis/mybatis-3