필자는 개발중 JPA를 위주로 사용한다.
JPA를 사용하다보면 Command의 쿼리는 정말 손쉽게 개발이 가능하지만 가끔 JPA로만 조회 쿼리를 작성할 때는 힘들때가 많았다.
동적쿼리나 복잡한 쿼리를 작성할 때는 정말 힘들 때도 많았다.
(JPQL ...)
사실 개발 시점에 IDE에서 알아차리기도 힘들고 테스트 작성도 어려움이 있었다.
그래서 조회쪽을 MyBatis와 같은 Mapper 를 별도로 사용해볼까? 고민이 들었지만
그럼 ORM을 사용하는 이유가 뭘까? 라는 의문도 나오게 되었다.
이부분에 대해 모순되는 점들이 있는 것 같아 검색을 해보니 Criteria, QueryDsl 등 여러 방법이 존재하였다.
그래서 QueryDsl 문법을 공부하고 실무에서 잘 사용중였는데 최근 Java Reflection 기술에 대해 공부, JPA의 프록시의 구현 방식 등을 공부하며 갑자기 QueryDsl에서는 어떻게 자바코드로 작성한 코드가 JPQL로 변환되는지 궁금해졌다.
서론은 길었지만 결론은 QueryDsl에 대해 여러 자료를 살펴보았고 이를 포스팅하기로 했다.
첫번째로는 QClass에 대해서이다.
과연 QClass가 뭘까? QueryDsl을 한번이라도 사용해본 개발자라면 QueryDsl 세팅 후 Complie 과정을 거치면 Qclass 가 생성되는 것을 확인한 적이 있을 것이다.
과연 이 클래스는 왜 생기는 것일까?
열심히 구글링하여 검색해보니 QueryDsl과 비슷한 Criteria에서도 비슷한 개념이 존재했다.
바로 JPA Metamodel class 이다.
사실 이 부분은 JPA에서 지원하는 기능이라고한다.
우선 JPA Metamodel 부터 살펴보자.
@Entity
@Table(name = "students")
public class Student {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private int id;
@Column(name = "first_name")
private String firstName;
@Column(name = "last_name")
private String lastName;
@Column(name = "grad_year")
private int gradYear;
// standard getters and setters
}
위와 같은 클래스 (엔티티) JPA Metamodel로 활용하기위해서는 JBoss 에서 제공하는 메타모델 생성 도구를 사용해야한다 . 기타 도구는 있긴하지만 스프링에서는 hibernate-jpamodelgen 을 권고하는 것 같다.
해당 의존성을 받고 JPA MetaModel을 생성하면
@Generated(value = "org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor")
@StaticMetamodel(Student.class)
public abstract class Student_ {
public static volatile SingularAttribute<Student, String> firstName;
public static volatile SingularAttribute<Student, String> lastName;
public static volatile SingularAttribute<Student, Integer> id;
public static volatile SingularAttribute<Student, Integer> gradYear;
public static final String FIRST_NAME = "firstName";
public static final String LAST_NAME = "lastName";
public static final String ID = "id";
public static final String GRAD_YEAR = "gradYear";
}
위와 같은 메타모델이 생성된다.
그럼 다시 돌아와서 QClass 와 생김새를 비교해보자.
/**
* QNoticeBoard is a Querydsl query type for NoticeBoard
*/
@Generated("com.querydsl.codegen.EntitySerializer")
public class QNoticeBoard extends EntityPathBase<NoticeBoard> {
private static final long serialVersionUID = 1698544114L;
private static final PathInits INITS = PathInits.DIRECT2;
public static final QNoticeBoard noticeBoard = new QNoticeBoard("noticeBoard");
public final QAbstractBoard _super = new QAbstractBoard(this);
// ...
}
해당 코드는 필자가 진행한 프로젝트 중 하나의 QClass 파일인데 위의 JPA MetaModel과 이 Qclass 의 공통점을 찾을 수 있을 것이다.
바로 properties 들이 static으로 이루어졌다는 것이다.
이점을 보았을 때 결국 자바 코드에서 -> JPQL로 변환할 때 만약 Static하지 않고 접근하기 위해서는 인스턴스를 별도로 생성하여 구현해야된다. 이점을 별도의 인스턴스 생성없이 바로 properties에 접근하기 위해서 static하게 만들지 않았을까 라는 의문이 생겨 찾아보니 맞는 것 같다.
'JPA' 카테고리의 다른 글
JPA N + 1, FetchJoin, EntityGraph (0) | 2022.03.18 |
---|---|
Spring JPA - Hibernate 에서 field가 Enum일때 @ColumnDefault는 어떻게? (0) | 2021.04.22 |