본문 바로가기

미역/Oracle & myBatis

<resultMap>, <association>, <collection>

 대충 말하자면, 테이블을 병합할 때마다 거기에 맞는 DTO를 새로 만든다면 무척이나 번거로울 테고 이 때 사용하면 유용한 게 <resultMap>이 된다. 

 

제대로 된 이해를 원한다면 다음 링크로
https://devlog-wjdrbs96.tistory.com/418
https://medium.com/webeveloper/mybatis-resultmap%EC%9D%B4%EB%9E%80-854a94df1f78

 

 

 아래 2개의 클래스가 있고(각 클래스와 똑같이 매치되는 DB도 있다고 생각하자)

모든 멤버필드를 조회하고자 하면 다음처럼 하면 된다.

public class User{
    private int userNo;
    private String userNm;
    private String phone;
    
    private Membership membershipVO;
}
public class Membership{
    private int userNo;
    private int membershipNo;
    private String membershipRank;
    private String terminationDate;
}
<!-- 
    id : resultMap 식별자
    type : 매핑될 클래스명 // Alias 처리를 안 해서 경로까지 적었다.
    property : 클래스 멤버필드 명
    column : 불러올 데이터베이스 항목 명
-->
<resultMap id="userMembership" type="~~.~~.~~.User"> 
    <result property="userNo" column="user_no" />
    <result property="userNm" column="user_nm" />
    <result property="phone" column="phone" />
    <association property="userMembersipVO" javaType="~~.~~.~~.Membership">
        <result property="membershipNo" column="membership_no" />
        <result property="membershipRank" column="membership_rank" />
        <result property="terminationDate" column="termination_date" />
    </association>
</resultMap>
    
<select id="selectAll" resultMap="userMembership">
    SELECT 
        user_no,
        user_nm,
        phone,
        membership_no,
        membership_rank,
        termination_date
    FROM user_table JOIN membership_table ON user_table.user_no = membership_table.user_no
 </select>

 JOIN된 테이블의 데이터를 가져오려고 DTO를 하나 더 만들지 말고 <resultMap>과 <association>을 사용하면 편하다. 

<association>을 사용하면 User클래스에 있는 Membership 객체 멤버필드에 대해서도 참조변수명을 통해 바인딩된다. 

 

 

 User 클래스에 객체 리스트가 있다면 다음처럼 하면 된다. 

public class User{
    private int userNo;
    private String userNm;
    private String phone;
    
    private List<Membership> membershipList;
}
<resultMap id="userMembership" type="~~.~~.~~.User"> 
    <result property="userNo" column="user_no" />
    <result property="userNm" column="user_nm" />
    <result property="phone" column="phone" />
    <!-- 리스트면 association이 아니고 collection을 사용한다. -->
    <!-- collection은 javaType이 아니고 ofType을 쓴다. -->
    <collection property="userMembersipVO" ofType="~~.~~.~~.Membership">
        <result property="membershipNo" column="membership_no" />
        <result property="membershipRank" column="membership_rank" />
        <result property="terminationDate" column="termination_date" />
    </collection>
</resultMap>
    
<select id="selectAll" resultMap="userMembership">
    SELECT 
        user_no,
        user_nm,
        phone,
        membership_no,
        membership_rank,
        termination_date
    FROM user_table JOIN membership_table ON user_table.user_no = membership_table.user_no
 </select>

 

 

 <resultMap>을 사용해서 계층적 데이터를 만들 수도 있다. 이번에는 User 클래스가 아래처럼 생겼다고 하자.

public class User{
    private int userNo;
    private String userNm;
    private String phone;
    
    private List<User> userList;
}

 User 클래스가 User 리스트를 멤버필드로 갖고 있는 경우이다. 그리고 우리는 userNm이 같은 사람별로 나누어서 데이터를 가져오고자 한다. 보통이라면 자바에서 조작하겠지만 <resultMap>을 사용하면 가능하다.

 

<resultMap id="userByNm" type="~~.~~.~~.User"> 
    <result property="userNm" column="user_nm" />
    <collection property="userList" ofType="~~.~~.~~.User">
        <result property="userNo" column="user_no" />
        <result property="phone" column="phone" />
    </collection>
</resultMap>
    
<select id="selectAll" resultMap="userByNm">
    SELECT 
        user_no,
        user_nm,
        phone
    FROM user_table
 </select>

 userNm이 같은 User객체들은 userList에 바인딩된다. 우리는 이제 같은 userNm을 가진 사람들의 데이터는 userList를 통해 수집할 수 

 

 

 같은 로직으로 membershipRank가 같고 terminationDate가 같은 사람별로 나누어서 데이터를 가져올 수도 있다.

public class Membership{
    private int userNo;
    private int membershipNo;
    private String membershipRank;
    private String terminationDate;
    
    private List<Membership> dateList;
    private List<Membership> infoList;
}
<resultMap id="membershipByRank" type="~~.~~.~~.Membership"> 
    <result property="membershipRank" column="membership_rank" />
    <collection property="dateList" javaType="java.util.ArrayList" resultMap="membershipByDate" />
</resultMap>

<resultMap id="membershipByDate" type="~~.~~.~~.Membership"> 
    <result property="terminationDate" column="termination_date" />
    <collection property="infoList" javaType="java.util.ArrayList" resultMap="membershipInfo" />
</resultMap>

<resultMap id="membershipInfo" type="~~.~~.~~.Membership"> 
    <result property="userNo" column="user_no" />
    <result property="membershipNo" column="membership_no" />
</resultMap>
    
<select id="selectAll" resultMap="membershipByRank">
    SELECT
        user_no,
        membership_no,
        membership_rank,
        termination_date
    FROM membership_table
 </select>

 이러면 처음 Membership 객체는 membershipRank와 dateList만 가지고 있다. 같은 membershipRank 별로 구분되어 dateList를 가지고 있고  dateList를 따라 들어가면 안의 Membership 객체는 terminationDate와 infoList만 가지고 있고 같은 terminationDate별로 구분되어 infoList를 가지고 있다. 

 우리는 이제 같은 membershipRank - terminationDate 별로 구분되어진 userNo, membershipNo를 수집할 수 있다. 

 

마지막은 회사에서 쓰고있는 방식이던데, 순간 뭔 코드지 하고 찾아보고 공부했다. 딱히 좋아보이진 않는다.

'미역 > Oracle & myBatis' 카테고리의 다른 글

COUNT(1)에 대해  (0) 2021.09.30