자바

MyBatis ResultMap - Collection, Association

chantleman 2024. 11. 20. 22: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

 

resultType과 resultMap 차이

resultType : Mybatis에서 SQL 쿼리의 결과를 매핑할 때 사용할 클래스의 타입을 지정하는 속성.이 속성에 지정된 클래스의 인스턴스로 결과를 매핑. SQL 쿼리 결과를 특정 클래스 타입으로 매핑하는

chantleman.tistory.com

 

 

 


 

 

 


Association

 

1: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