[Mybatis]resultMap을 이용한 1:N select시 주의 점

Published on: 2013. 11. 14. 14:07 by louis.dev
mybatis에서 테이블간의 1:N관계를 select 할때 resultMap을 통한 일종의 서브쿼리 형식으로 데이터를 가져올수 있다. 예를들어 게시판(BOARD)라는 테이블과 댓글(COMMENT)라는 테이블이 있고, 하나의 게시글에는 여러개의 댓글이 생성될수 있음으로 게시판과 댓글의 관계는 1:N관계이다. 이런 구조를 자바 코드로 클래스를 만들어 보면 다음과 같다.
class  Board{
	private String board;
	private String title;
	private String content;
	private String writer;
	private List<Comment> comments;

	//getter, setter 생략
}
소스에서도 볼수 있듯이 Board라는 클래스는 comment의 List형태인 comments라는 프로퍼티를 가지고 있게된다. 이렇게 1:N의 구조일때 Mybatis에서는 쿼리를 저장하는 xml파일(iBatis에서는 sqlmap으로 불렀으나 mybatis에서는 mapper라고 부름)에 resultMap 엘리먼트로 다음과 같이 설정할 수 있다.
<resultMap id="boradResult" type="net.krespo.mybatis.Board">
	<result property="boardid" column="BOARDID"/>
	<result property="title" column="TITLE"/>
	<result property="content" column="CONTENT"/>
	<collection property="comments" column="BOARDID" javaType="java.util.ArrayList" ofType="net.krespo.mybatis.Comment" select="getCommentListById"/>
</resultMap>

<select id="getBoardById" resultMap="boardResult">
	SELECT boardid, title, content FROM board WHERE boardid = #{boardid}
</select>
<select id="getCommentListById" resultType="net.krespo.mybatis.Comment">
	SELECT commentid, boardid, writer, content FROM comment WHERE boardid = #{boardid}
</select>
위와같이 getBoardById라는 쿼리는 게시글을 읽어올때 실행되는 쿼리이다. 이때 getBoardByIdresultMap으로 boardResult를 지정하고 있고 boardResultcollection 선언을 통해(select="getCommentListByBoardId" 쿼리를 실행할때 parameter는 column으로 선언된 boardid를 가지고) 하위 댓글 리스트를 가져온다. 만약 댓글을 가져올때 자기가 쓴글에 자기가 쓴 댓글을 가져오려면 어떻게 해야할까?  그럴때는 boardid와 writer를 getCommentListById로 넘겨주어야 한다. 이처럼 여러개의 파라미터를 collection에서 넘길때는
column="{prop1=COLUMN1, prop2=COLUMN2}"
로 쓰면된다. . 즉
<collection property="comments" column="{boardid=BOARDID,writer=WRITER}" javaType="java.util.ArrayList" ofType="net.krespo.mybatis.Comment" select="getMyCommentListById"/>

<select id="getMyCommentListById" parameterType="java.util.Map" resultType="net.krespo.mybatis.Comment">
	SELECT id, writer, content FROM comment WHERE boardid = #{boardid} AND writer = #{writer}
</select>
로 쓰면 된다. 이때 select문에서 사용하는 파라미터명과 collection에서 선언한 column의 prop1, prop2명이 반드시 동일해야 한다.(column="{prop1=COLUMN1, prop2=COLUMN2}", #{prop1}, #{prop2}) 그리고 또 반드시 주의 해야 할점은 파라미터가 한개만 전달할때는(맨 첫번째 예제인 게시글에 댓글을 가져올때) getCommentListById에 parameterType을 지정하지 않아도 됐었다. 그러나 위와 같이 collection으로 파라미터를 여러개 전달해야 할때는 반드시 parameterType="java.util.Map"을 지정해 줘야 한다. 그렇지 않으면 다음과 같은 에러를 내뿜는다.
Caused by: org.apache.ibatis.reflection.ReflectionException: There is no setter for property named 'boardid' in 'class java.lang.Object'