Framework/myBatis
[Mybatis]resultMap을 이용한 1:N select시 주의 점
louis.dev
2013. 11. 14. 14:07
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라는 쿼리는 게시글을 읽어올때 실행되는 쿼리이다. 이때 getBoardById는 resultMap으로 boardResult를 지정하고 있고 boardResult의 collection 선언을 통해(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'