简体   繁体   中英

How to set argument in myBatis mapper from another mapper

I have some problems with mapping in myBatis.

I have pojo class

public class Video {
    private int id;
    private String title;
    private Set<Person> actors;
    ...
    getters & setters
}

I'm have interface PersonMapper

public interface PersonMapper {
@Select("${query}")
    Set<Person> getByFilmId(@Param("id") long id, @Param("query") PersonByFilmQueries query);

enum PersonByFilmQueries {

        ACTORS_BY_FILM(
                "select " +
                "   * " +
                "from " +
                "   actors a, " +
                "   film_actors fa " +
                "where " +
                "   fa.actor_id = a.id " +
                "and fa.film_id = #{id}"),
        ....
        WRITERS_BY_FILM(
                "select "+
                "* " +
                "from " +
                "writers w, " +
                "film_writers fw " +
                "where " +
                "fw.writer_id = w.id " +
                "and fw.film_id = #{id}");
        private String query;

        PersonByFilmQueries(String query) {
            this.query = query;
        }

        @Override
        public String toString() {
            return query;
        }
    }
}

I am try to reuse this select from another xml mapper (VideoMapper.xml).

<mapper namespace="ru.common.mapper.VideoMapper">
    <resultMap id="video" type="Video">
    <id property="id" column="id"/>
    <result property="title" column="title"/>
    </resultMap>
    <collection property="actors" javaType="HashSet" ofType="Person" column="id" 
    select="ru.common.mapper.PersonMapper.getByFilmId">
    </collection>
</resultMap> 

I'm trying to add a collection of Person to Video POJO. But I do not understand how to set the second argument in getByFilmId enum with sql. Is there any easy way to do this? If I call this mapper from Java then there are no problems, everything works

In general you can specify multiple parameters to the nested select for association or collection.

If the query parameters was simple String (and not an enum) you could add a column to the main query that return list of videos like this:

select id, title, ..., 'ACTORS_BY_FILM' query_type
from video

Then you modify the mapping for collection:

 <collection property="actors" javaType="HashSet" ofType="Person" column="{id=id,query=query_type}" 
select="ru.common.mapper.PersonMapper.getByFilmId">

This way columns id and query_type from the main query would be passed as parameters to nested select.

In your case you need that mybatis invoke constructor on a passed string parameter and I don't think mybatis supports this.

One way you can try to overcome this. I'm not sure it will work as you are already on the grey territory when you are using double substitution. I would say this is not an intended behaviour of mybatis.

But you can try. So change the mapper method to accept string.

Then you can create a helper static method that converts a name of the query to the query text:

 public class PersonByFilmQueryBuilder {

     public static String getQuery(String queryId) {
          return PersonByFilmQueries.valueOf(queryId);
     }
 }

Now you can use this static method in the OGNL expression in select like this:

@Select("${@com.mycompany.myapp.PersonByFilmQueryBuilder@getQuery(query)}")
Set<Person> getByFilmId(@Param("id") long id, @Param("query") String query);

I'm not quite sure that in this phase of query generation mybatis does use full-blown OGNL expression. If it does this will work.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM