JPA-12 nativeQuery

yj k·2023년 4월 11일
0

jpa

목록 보기
14/14

nativeQuery

네이티브 SQL :
네이티브 SQL은 SQL을 개발자가 직접 정의해서 사용할 수 있도록 해주는 수동 모드이다.

(JPQL은 데이터베이스들이 따로 지원하는 것들에 있어 모든 것을 SQL로 자동으로 바꿔주지 않는다. 인라인 뷰, UNION, INTERSECT 등등)

JDBC API와의 차이점 :
직접 SQL을 작성하는 JDBC API와는 달리 네이티브 SQL은 JPA의 영속성 컨텍스트의 기능을 그대로 사용할 수 있다.


네이티브 쿼리 API의 3가지 종류

  1. 결과 타입 정의
    public Query createNativeQuery(String sqlString, Class resultClass);

  2. 결과 타입을 정의할 수 없을 때
    public Query createNativeQuery(String sqlString);

  3. 결과 매핑 사용
    public Query createNativeQuery(String sqlString, String resultSetMapping);



1. 결과 타입 정의

  • 우리가 사용하는 DBMS의 고유한 SQL문법을 작성한다. 위치 기반 파라미터로만 사용이 가능하다.

  • 일부 컬럼만 조회하는 것은 불가능하다.

  • 모든 컬럼 값을 매핑하는 경우에만 타입을 특정할 수 있다. 일부 컬럼만 조회하고 싶은 경우는 Object[] 또는 스칼라 값을 별도로 담을 클래스를 정의해서 사용해야한다.

  • 영속성 컨텍스트에서 관리하는 객체이다.


2. 결과 타입 정의할 수 없는 경우

  • 결과 타입을 특정하는 것 자체가 불가능하다. 엔티티로 매핑 시킬 경우에만 클래스 타입을 입력한다.
List<Object[]> menuList = entityManager.createNativeQuery(query).getResultList();

//List<Object[]> menuList = entityManager.createNativeQuery(query, Object[].class).getResultList();



3. 결과 매핑 사용

자동 결과 매핑 사용

@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")}
				)               
              




NamedNativeQuery

어노테이션 방식

네이티브 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"
            )
        }
)




XML 방식

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>

0개의 댓글