-
mybatis: resultMap ( 1:1 / 1:n select )기타 2023. 6. 21. 09:25
이번 프로젝트에서는 DB를 기능마다 나눠서, 기능을 추가하거나 데이터를 관리하기 편리하게
다음과 같이 설계했다.
다만 데이터를 select 하는데 있어서 두 가지 방법에 대해 이해가 필요했다
1 : 1 관계
두 가지 테이블을 join 할 때, 각 각 한 개의 행끼리 매치가 되도록 만드는 것이다.
위의 erd에서는 주문 테이블과 주문취소 테이블이 1:1 방법이다.
1개의 주문에는 해당 주문이 취소되었는지 아닌지 확인하는 주문 취소 열이 필요하다.
SELECT * FROM `order` o JOIN order_cancel oc ON o.order_id = oc.order_id WHERE oc.state = 'normal'
이렇게 쿼리문을 작성하면, 주문 테이블과 주문 취소 테이블을 order_id 값을 기준으로 조인하고
주문 취소 테이블의 state 열의 값이 'normal'인 경우의 데이터만 select 할 수 있다.
결과로, 1개의 행에 주문에 대한 정보와 주문 취소 여부가 나타나게 된다.
1 : n 관계
특정 테이블의 1개의 행과 다른 테이블의 여러개의 행이 관계성을 가질 때는 조금 복잡해진다.
예를 들어서 1개의 주문에는 여러개의 주문된 제품과 제품의 갯수가 존재한다.
SELECT * FROM `order` o JOIN order_product oc ON o.order_id = op.order_id
해당 쿼리문을 실행시키면 1개의 주문 정보와 여러개의 ( 제품, 구매 수량 ) 데이터를 가지기 때문에
select의 결과로 여러개의 행을 불러온다.
다음과 같은 경우, resultMap을 사용해서 중복되는 데이터 (주문 정보) 를 하나로 만들고
여러개의 데이터 ( 제품, 구매 수량 ) 을 LIST 형태로 저장해서
1개의 VO에 저장할 수 있다.
resultMap 사용하기
<!-- 출하 계획표 불러오기 --> <select id="list" resultMap="adminOrderResultMap"> SELECT o.order_id AS orderId, DATE_FORMAT(o.delivery_date, '%Y-%m-%d') AS deliveryDate, DATE_FORMAT(o.order_date, '%Y-%m-%d') AS orderDate, c.hospital AS hospital, c.name AS name, c.address AS address, c.email AS email, c.phone AS phone FROM `order` o JOIN order_cancel oc ON o.order_id = oc.order_id JOIN customer c ON o.customer_id = c.customer_id WHERE oc.state = 'normal' <choose> <when test="orderId != 0"> AND o.order_id = #{orderId} </when> </choose> ORDER BY o.order_id DESC <!-- LIMIT ${(pageNum-1)*amount}, #{amount} --> </select> <!-- 주문한 물건 목록 불러오기 (이름, 갯수) --> <select id="selectOrderedProductList" parameterType="control.suppliers.model.AdminOrderVO" resultType="control.suppliers.model.OrderedProductVO"> Select op.count AS count, p.name AS product, p.code AS code, p.count AS stock, p.tax AS tax, p.price AS price From ordered_product op LEFT JOIN product p ON op.product_id = p.product_id WHERE op.order_id = #{orderId} </select>
프로젝트에서 사용했던 쿼리문이다.
해당 쿼리문을 사용해서, 주문에 대한 정보(1개)와 주문 된 물건들에 대한 정보, 물건의 갯수 등(여러개)을 조회하고 싶었다.
우선은, 주문에 대한 정보를 select 하기 위해 list쿼리의 결과물을 resultMap으로 설정했고
<!-- 출하 계획표 resultMaps --> <resultMap id="adminOrderResultMap" type="control.suppliers.model.AdminOrderVO"> <id property="orderId" column="orderId" javaType="int"/> <result property="deliveryDate" column="deliveryDate" javaType="String"/> <result property="orderDate" column="orderDate" javaType="String"/> <result property="hospital" column="hospital" javaType="String"/> <result property="name" column="name" javaType="String"/> <result property="address" column="address" javaType="String"/> <result property="email" column="email" javaType="String"/> <result property="phone" column="phone" javaType="String"/> <collection column="orderId = orderId" property="orderedProduct" javaType="List" ofType="control.suppliers.model.OrderedProductVO" select="selectOrderedProductList"/> </resultMap>
resultMap을 작성했다.
id 태그 : 해당 resultMap데이터의 key (index)가 될 column을 로 설정해야한다.
위의 코드에서는 주문번호로 설정했다.
property에는 해당 데이터가 저장될 변수명을 작성하고, column에는 데이터를 가져올 열의 이름을 작성했다.
result 태그 : 단 하나의 데이터를 저장하는데 사용했다. 이 코드에서는 주문 1개에 대한 정보를 result 태그에 저장했다
collection 태그 : 해당 태그는 여러개의 데이터를 List 형태로 저장할 수 있다.
이 코드에서는 collection 태그의 결과물의 타입을 ofType으로 VO를 지정했고, VO에 넣을 데이터를 select 문을 새로 연결해서 가져오도록 만들었다.
만약 select 문을 사용하지 않으면, list 쿼리문의 테이터를 id 나 result 형태로 가져올 수 있다.
또한 resultMap을 사용할 때는 꼭 태그들의 순서를 지켜야한다 ( 위의 코드에서 id - result - collection 순서가 지켜지지 않으면 에러가 발생한다. )
resultMap의 결과물은
이 VO에 저장해서 사용할 수 있다.
'기타' 카테고리의 다른 글
스크래핑 시 쿠키 받아오기 (0) 2023.08.25 스크래핑 기초 (0) 2023.08.09 if문과 논리연산자 (0) 2023.06.15 코드 포맷터 ( Prettier ) 사용하기 (0) 2023.06.15 ajax를 사용하지 않는 방법 생각해보기 (1) 2023.06.12