Programing/JPA

named-native-query @Query에 String을 +로 연결하는게 너무 싫어요!

리커니 2023. 8. 8. 15:19
반응형

JPA를 사용하다 보면 querydsl에서 지원하지 않거나, 복잡한 쿼리를 작성해야 할 때

org.springframework.data.jpa.repository.Query @Query 를 사용해야 하는 경우가 있습니다.

이런 경우 query를 String으로 연결해서 작성해야 하기 때문에 

디버깅 해서 쿼리를 확인해야 할 때나 그 반대의 경우 매~우 불편하죠.

 

Link : https://aljjabaegi.tistory.com/694#2._JPQL_(_Java_Persistence_Query_Language)_and_nativeQuery 

 

Querydsl vs Criteria API vs QueryMethod vs JPQL 비교

이전 포스팅에서 Querydsl 을 설정하는 방법을 알아보았습니다. Link : https://aljjabaegi.tistory.com/691 Springboot 2.x + queryDSL 설정 방법 JPA를 사용하게 되면 Query method를 사용하면 간단한 조건의 작업들은 가

aljjabaegi.tistory.com

위의 링크를 보시면 JPQL, NativeQuery의 작성 방식을 보실 수 있습니다.

이러한 단점(?!) 을 보완하기 위해,

이전의 Mybatis 처럼 XML 에서 쿼리를 작성할 수 있게 하는 방법을 알아보도록 하겠습니다.

 

1.  application.yml 에 xml resources 추가

spring:
    jpa:
        mapping-resources:
         - query/test.xml

쿼리를 작성 할 xml 파일의 경로를 추가해줍니다. wildcard 로는 동작하지 않으니 각각 추가해줍니다.

위에서 설정한 경로는 resources/query/test.xml 입니다. 

추가적으로 xml을 더 추가해야 한다면 아래와 같이 추가해주시면 됩니다.

 

spring:
    jpa:
        mapping-resources:
         - query/test.xml
         - query/test2.xml

querydsl로 작성이 어렵거나 지원이 되지 않는 부분만 작성을 하는 것이니 그렇게 많은 xml 추가는 필요하시지 않을 것으로 판단됩니다.

 

2. xml 작성

<?xml version="1.0" encoding="UTF-8"?>
<entity-mappings xmlns="http://xmlns.jcp.org/xml/ns/persistence/orm"
                 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                 xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence/orm http://xmlns.jcp.org/xml/ns/persistence/orm_2_2.xsd"
                 version="2.2">
    <named-native-query name="M_OP_CD.getNamedQueryTest" result-set-mapping="code">
        <query>
            <![CDATA[
            SELECT GRP_CD_ID AS grpCdId
                 , CD_ID AS cdId
                 , CD_NM AS cdNm
              FROM M_OP_CD
              WHERE GRP_CD_ID < :grpCdId
            ]]>
        </query>
    </named-native-query>

    <sql-result-set-mapping name="code">
        <constructor-result target-class="패키지.TestDTO">
            <column name="grpCdId"/>
            <column name="cdId"/>
            <column name="cdNm"/>
        </constructor-result>
    </sql-result-set-mapping>
</entity-mappings>

xml 파일 내 위와 같이 작성을 합니다.

named-native-query의 query태그 안에 query를 작성하면 되고, 

named-native-query의 name 속성에는 repository의 'Enitty명.호출할메소드명' 을 설정하시면 됩니다.

result-set-mapping은 조회된 결과를 매핑할 객체를 설정해주면되는데,

위에서 보시는 것과 같이 sql-result-set-mapping의 name과 맞추어 주시면 됩니다.

 

3. repository 에 추가

이제 repository에 메서드를 추가해줍니다.

@Repository
public interface CodeRepository extends JpaDynamicRepository<M_OP_CD, M_OP_CD_KEY> {

    @Query(nativeQuery = true)
    List<TestDTO> getNamedQueryTest(@Param("grpCdId") String grpCdId);
    
}

 파라미터의 경우 nativeQuery를 쓸 때와 같이 @Param 을 사용하여 전달해주시면 됩니다. (받을 때는 :파라미터명)

 

이제 메소드를 호출하면 결과를 얻으실 수 있습니다.

List<TestDTO> testList = codeRepository.getNamedQueryTest("QUERY_DSL_TEST");

 

TestDTO 참고하세요~

DTO에 생성자가 없을 경우 오류가 발생하게 되니 꼭 추가해주세요!

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;

@AllArgsConstructor
@Getter
@Setter
public class TestDTO {
    private String grpCdId;
    private String cdId;
    private String cdNm;
}

 

다중 DB 설정 시에는 LocalContainerEntityManagerFactoryBean의 mappingResources로 추가해 줍니다.

setMappingresources() 사용.

@Configuration
public class dbOneDbConfig {
    @Bean
    @Primary
    public LocalContainerEntityManagerFactoryBean oneEntityManager() {
        LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
        factory.setDataSource(baseDataSource());
        factory.setPackagesToScan("적용할 Entity의 패키지 경로");
        factory.setMappingResources("xml 경로");
        factory.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
        factory.getJpaPropertyMap().put("hibernate.dialect", "org.hibernate.dialect.PostgreSQLDialect");
        return factory;
    }
}
반응형