네이티브 SQL :
네이티브 SQL은 SQL을 개발자가 직접 정의해서 사용할 수 있도록 해주는 수동 모드이다.
JDBC API와의 차이점 :
직접 SQL을 작성하는 JDBC API와는 달리 네이티브 SQL은 JPA의 영속성 컨텍스트의 기능을 그대로 사용할 수 있다.
네이티브 쿼리 API의 3가지 종류
결과 타입 정의
public Query createNativeQuery(String sqlString, Class resultClass);
결과 타입을 정의할 수 없을 때
public Query createNativeQuery(String sqlString);
결과 매핑 사용
public Query createNativeQuery(String sqlString, String resultSetMapping);
우리가 사용하는 DBMS의 고유한 SQL문법을 작성한다. 위치 기반 파라미터로만 사용이 가능하다.
일부 컬럼만 조회하는 것은 불가능하다.
모든 컬럼 값을 매핑하는 경우에만 타입을 특정할 수 있다. 일부 컬럼만 조회하고 싶은 경우는 Object[] 또는 스칼라 값을 별도로 담을 클래스를 정의해서 사용해야한다.
영속성 컨텍스트에서 관리하는 객체이다.
List<Object[]> menuList = entityManager.createNativeQuery(query).getResultList();
//List<Object[]> menuList = entityManager.createNativeQuery(query, Object[].class).getResultList();
자동 결과 매핑 사용
@SqlResultSetMapping
매핑에 사용할 엔티티 클래스 영역에 붙여준다.
@Column으로 매핑 설정이되어 있는 경우 사용
속성
name
: 결과 매핑 이름
entities
: @EntityResult를 사용해서 '엔티티'를 결과로 매핑
columns
: @ColumnResult를 사용해서 '컬럼'을 결과로 매핑
쿼리 실행 시 name
속성에 설정한 이름 사용(여기서는 categoryCountAutoMapping)
@Entity(name="section01_category")
@Table(name="TBL_CATEGORY")
@SqlResultSetMappings(
value=
{
@SqlResultSetMapping(
name="categoryCountAutoMapping",
entities = {@EntityResult(entityClass = Category.class)},
columns = {@ColumnResult(name="MENU_COUNT")}
)
public class Category {
@Id
@Column(name="CATEGORY_CODE")
... 생략
쿼리 실행 문
Query nativeQuery = entityManager.createNativeQuery(query, "categoryCountAutoMapping");
수동 결과 매핑 사용
@SqlResultSetMapping
매핑에 사용할 엔티티 클래스 영역에 붙여준다.
매핑 설정을 수동으로 해주는 경우 - @Column은 생략 가능
@EntityResult
'엔티티'를 결과로 매핑
@FieldResult
컬럼명과 필드명을 직접 매핑
쿼리 실행 시 name
속성에 설정한 이름 사용(여기서는 categoryCountManualMapping)
@SqlResultSetMapping(
name="categoryCountManualMapping",
entities = {
@EntityResult( entityClass = Category.class, fields = {
@FieldResult(name="categoryCode", column="CATEGORY_CODE"),
@FieldResult(name="categoryName", column="CATEGORY_NAME"),
@FieldResult(name = "refCategoryCode", column = "REF_CATEGORY_CODE"),
})
},
columns = {@ColumnResult(name = "MENU_COUNT")}
)
네이티브 SQL도 JPQL처럼 @NamedNativeQuery
를 사용해 정적 SQL을 만들어두고 쓸 수 있다.
사용할 엔티티 클래스 영역에 붙여준다
@NamedNativeQueries(
value = {
@NamedNativeQuery(
name = "Category.menuCountOfCategory",
query = "SELECT\n"
+ " A.CATEGORY_CODE, A.CATEGORY_NAME, A.REF_CATEGORY_CODE, NVL(V.MENU_COUNT, 0) MENU_COUNT\n"
+ " FROM TBL_CATEGORY A\n"
+ " LEFT JOIN (SELECT COUNT(*) AS MENU_COUNT, B.CATEGORY_CODE \n"
+ " FROM TBL_MENU B\n"
+ " GROUP BY B.CATEGORY_CODE) V ON (A.CATEGORY_CODE = V.CATEGORY_CODE)\n"
+ " ORDER BY 1",
resultSetMapping = "categoryCountAutoMapping2"
)
}
)
persistence.xml에 xml에 작성한 query문을 읽어오기 위한 코드 작성.
<!-- category-query.xml을 읽어오기 위한 코드 -->
<mapping-file>/META-INF/category-query.xml</mapping-file>
category-query.xml에 실행할 쿼리문 작성
name
쿼리문 실행 시 name 속성에 작성된 이름으로 호출(여기서는 Category.menuCountOfCategoryXML)
<named-native-query name="Category.menuCountOfCategoryXML" result-set-mapping="categoryCountXmlMapping">
<query>
SELECT
A.CATEGORY_CODE
, A.CATEGORY_NAME
, A.REF_CATEGORY_CODE
, NVL(V.MENU_COUNT, 0) MENU_COUNT
FROM TBL_CATEGORY A
LEFT JOIN (SELECT COUNT(*) AS MENU_COUNT
, B.CATEGORY_CODE
FROM TBL_MENU B
GROUP BY B.CATEGORY_CODE
) V ON (A.CATEGORY_CODE = V.CATEGORY_CODE)
ORDER BY 1
</query>
</named-native-query>
사용할 엔티티 클래스 영역에 붙여준다.
@SqlResultSetMapping(name = "categoryCountAutoMapping2",
entities = {@EntityResult(entityClass = Category.class)},
columns = {@ColumnResult(name = "MENU_COUNT")}
)
엔티티 클래스 영역에 붙여준 설정과
xml파일의 설정 속성 이름을 맞춰준다.
<sql-result-set-mapping name="categoryCountXmlMapping">
<entity-result entity-class="com.greedy.section02.named.Category"/>
<column-result name="MENU_COUNT"/>
</sql-result-set-mapping>