named-native-query @Query에 String을 +로 연결하는게 너무 싫어요!
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
위의 링크를 보시면 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;
}
}