- MyBatis ResultMap - Collection, Association2024년 11월 20일
- chantleman
- 작성자
- 2024.11.20.:03
데이터베이스 결과를 자바 객체에 매핑하는 방법 중에 resultMap 과 resultType이 있당
자바에서는 카멜 표기법을 사용하고, sql에서는 스네이크 표기법을 사용하는데
db의 컬럼명과 자바의 프로퍼티를 매핑하기 위해 resultType이 아닌 resultMap을 사용한당
혹은 테이블 조인이 있을 때 테이블간의 관계를 매핑하기 위해 resultMap을 사용한당
조인없을때는 resultType 사용
다중 파일 업로드 같이 다대다 관계를 나타낼때 테이블 조인(left outer join)을 하게 되는데 그때 객체들을 매핑시키기위해 resultMap의 association과 collection을 사용한당
db 컬럼명 - 자바 프로퍼티 연결을 위해 sql에서 아래코드 실행 후 resultMap 태그 안에 넣어주깅
SELECT COLUMN_NAME , DATA_TYPE , CASE WHEN DATA_TYPE='NUMBER' THEN 'private int ' || FN_GETCAMEL(COLUMN_NAME) || ';' WHEN DATA_TYPE IN('VARCHAR2','CHAR') THEN 'private String ' || FN_GETCAMEL(COLUMN_NAME) || ';' WHEN DATA_TYPE='DATE' THEN 'private Date ' || FN_GETCAMEL(COLUMN_NAME) || ';' ELSE 'private String ' || FN_GETCAMEL(COLUMN_NAME) || ';' END AS CAMEL_CASE , '<result property="'||FN_GETCAMEL(COLUMN_NAME)||'" column="'||COLUMN_NAME||'"/>' RESULTMAP FROM ALL_TAB_COLUMNS WHERE TABLE_NAME = '테이블(대문자)' AND OWNER = '계정(대문자)';
https://chantleman.tistory.com/entry/resultType%EA%B3%BC-resultMap-%EC%B0%A8%EC%9D%B4
Association1:1 관계를 매핑할 때 사용
<resultMap id="blogResult" type="Blog"> <id property="id" column="blog_id"/> <result property="title" column="blog_title"/> <association property="author" javaType="Author"> <id property="id" column="author_id"/> <result property="username" column="author_username"/> </association> </resultMap>
Blog 객체는 하나의 Author 객체를 가지고,
association 요소는 Author 객체를 Blog 객체의 author 프로퍼티에 매핑한당
Collection
1:N 관계를 매핑할 때 사용
<resultMap id="blogWithPostsResult" type="Blog"> <id property="id" column="blog_id"/> <result property="title" column="blog_title"/> <collection property="posts" ofType="Post"> <id property="id" column="post_id"/> <result property="subject" column="post_subject"/> <result property="body" column="post_body"/> </collection> </resultMap>
Blog 객체는 여러개의 Post 객체를 가지고,
collection 요소는 여러 Post 객체를 Blog 객체의 posts 프로퍼티에 매핑한당
- property : 매핑할 자바 객체의 프로퍼티 이름
- javaType : 매핑할 자바 객체의 타입 (association 에서 사용)
- ofType : 컬렉션에 포함된 객체의 타입 (collection 에서 사용)
예시
학생의 사진을 등록하는 기능을 넣는다고 하장
학생(Stud) : 사진(FileDetail) = 다 : 다 이기때문에 중간에 연결다리 테이블(FileGroup) 하나 만들어주장
↓ FileGroupVO ↓
public class FileGroupVO { private long fileGroupNo; private Date fileRegdate; }
↓ StudVO ↓
public class StudVO { private String email; private String password; private String rememberMe; private long fileGroupNo; private MultipartFile[] uploadFiles; }
↓ FileDetailVO ↓
public class FileDetailVO { private int fileSn; private long fileGroupNo; private String fileOriginalName; private String fileSaveName; private String fileSaveLocate; private long fileSize; private String fileExt; private String fileMime; private String fileFancysize; private Date fileSaveDate; private int fileDowncount; }
이렇게 세개의 vo가 있고,
studVO → fileGroupVO
fileDetailVO → fileGroupVO
이렇게 참조하고 있다고 하장
public class FileGroupVO { private long fileGroupNo; private Date fileRegdate; private int fileSn; private long fileGroupNo; private String fileOriginalName; private String fileSaveName; private String fileSaveLocate; private long fileSize; private String fileExt; private String fileMime; private String fileFancysize; private Date fileSaveDate; private int fileDowncount; }
FileGroupVO에 fileDetailVO 객체들을 넣어야 하기 때문에 위와 같게 된당
하지만 위의 방식처럼 하는 것보다는 아래 방식처럼 하는 것이 더 간단하당 !!
public class FileGroupVO { private long fileGroupNo; private Date fileRegdate; //파일그룹 : 파일상세 = 1 : N private List<FileDetailVO> fileDetailVOList; }
이를 xml 파일의 resultMap에서 매핑을 하게 되는데
FileGroup과 FileDetail은 1:N 관계이기 때문에 collection을 사용해서 아래처럼 매핑한당
<resultMap type="kr.or.ddit.vo.FileGroupVO" id="fileGroupMap"> <result property="fileGroupNo" column="FILE_GROUP_NO"/> <result property="fileRegdate" column="FILE_REGDATE"/> <collection property="fileDetailVOList" resultMap="fileDetailMap"></collection> </resultMap>
<resultMap type="kr.or.ddit.vo.FileDetailVO" id="fileDetailMap"> <result property="fileSn" column="FILE_SN"/> <result property="fileGroupNo" column="FILE_GROUP_NO"/> <result property="fileOriginalName" column="FILE_ORIGINAL_NAME"/> ... </resultMap>
마찬가지로 아래처럼 StudVO에 FileGroupVO 객체들을 넣어야 하지만
public class StudVO { private String email; private String password; private String rememberMe; private long fileGroupNo; private MultipartFile[] uploadFiles; private long fileGroupNo; private Date fileRegdate; }
이렇게 하는 것이 더 간단!
public class StudVO { private String email; private String password; private String rememberMe; private long fileGroupNo; private MultipartFile[] uploadFiles; //학생 : 파일 그룹 = 1 : 1 (1:1은 리스트가 없음) private FileGroupVO fileGroupVO; }
또 이를 xml파일에서 매핑하는데
둘은 1:1 관계이기때문에 collection이 아닌 association을 사용하여 아래처럼 매핑한당
<resultMap type="kr.or.ddit.vo.StudVO" id="studMap"> <result property="email" column="EMAIL"/> <result property="password" column="PASSWORD"/> <result property="rememberMe" column="REMEMBER_ME"/> <result property="fileGroupNo" column="FILE_GROUP_NO"/> <association property="fileGroupVO" resultMap = "fileGroupMap"></association> </resultMap>
<resultMap type="kr.or.ddit.vo.FileGroupVO" id="fileGroupMap"> <result property="fileGroupNo" column="FILE_GROUP_NO"/> <result property="fileRegdate" column="FILE_REGDATE"/> <collection property="fileDetailVOList" resultMap="fileDetailMap"></collection> </resultMap>
resultMap 세팅해준 후 select 쿼리문에서 resultMap id에 맞게 매핑해준당
<select id="detail" parameterType="kr.or.ddit.vo.StudVO" resultMap="studMap"> select s.EMAIL, s.PASSWORD, s.REMEMBER_ME, s.FILE_GROUP_NO , fg.FILE_REGDATE, fd.FILE_SN ,fd.FILE_ORIGINAL_NAME, fd.FILE_SAVE_NAME , fd.FILE_SAVE_LOCATE, fd.FILE_SIZE, fd.FILE_EXT, fd.FILE_MIME , fd.FILE_FANCYSIZE, fd.FILE_SAVE_DATE, fd.FILE_DOWNCOUNT from stud s left outer join file_group fg on s.file_group_no = fg.file_group_no left outer join file_detail fd on s.file_group_no = fd.file_group_no where s.email = #{email} </select>
그리고 데이터 꺼낼 때는 이런식으로 타고 타고 들어가서 꺼내야한당!!
<c:forEach var="list" items="${studVO.fileGroupVO.fileDetailVOList}"> <div class="col-sm-1"> <img width="200px" class="img-fluid" src="${list.fileSaveLocate}" alt="Photo"> </div> </c:forEach>
public class StudVO { private String email; private String password; private String rememberMe; private long fileGroupNo; private MultipartFile[] uploadFiles; private long fileGroupNo; private Date fileRegdate; private int fileSn; private long fileGroupNo; private String fileOriginalName; private String fileSaveName; private String fileSaveLocate; private long fileSize; private String fileExt; private String fileMime; private String fileFancysize; private Date fileSaveDate; private int fileDowncount; }
만약 굳이 굳이 이렇게 하나의 vo에 합쳐서 하고싶다면
resultMap할 때도 아래처럼 합쳐서 쓰면 된당
<resultMap type="kr.or.ddit.vo.StudVO" id="studMap"> <result property="email" column="EMAIL"/> <result property="password" column="PASSWORD"/> <result property="rememberMe" column="REMEMBER_ME"/> <result property="fileGroupNo" column="FILE_GROUP_NO"/> <result property="fileRegdate" column="FILE_REGDATE"/> <result property="fileSn" column="FILE_SN"/> <result property="fileOriginalName" column="FILE_ORIGINAL_NAME"/> <result property="fileSaveName" column="FILE_SAVE_NAME"/> <result property="fileSaveLocate" column="FILE_SAVE_LOCATE"/> <result property="fileSize" column="FILE_SIZE"/> <result property="fileExt" column="FILE_EXT"/> <result property="fileMime" column="FILE_MIME"/> <result property="fileFancysize" column="FILE_FANCYSIZE"/> <result property="fileSaveDate" column="FILE_SAVE_DATE"/> </resultMap>
정리
MyBatis에서 SQL 결과를 객체로 변환하여 관계 매핑할 때 Association과 Collection을 사용하여 객체간의 관계를 표현한당. 복잡한 조인 쿼리 결과를 객체 그래프로 변환할 때 중첩된 객체 구조를 쉽게 표현할 수 있기 때문에 association과 collection 매핑이 필수적이당.
또 매핑을 통해 지연 로딩이나 즉시 로딩같은 고급 기능을 설정하여 성능을 최적화시킬 수 있당
728x90'자바' 카테고리의 다른 글
자바 기초 (0) 2024.12.22 iterator (1) 2024.11.09 selectkey (0) 2024.10.15 forward, sendredirect (0) 2024.10.15 전자정부프레임워크 개발환경구축 (0) 2024.10.11 다음글이전글이전 글이 없습니다.댓글