우리가 평소에 만드는 Repository 처럼,
@Repository
, @Transactional(readOnly=true)
어노테이션을 가진다!
save 같은 친구들에겐 따로 @Transactional
을 달아주면서 처리!
새로운 엔티티면 저장 (persist)
새로운 엔티티가 아니면 병합 (merge) <- 그냥 바꿔치기 해버리기!!
(잘 활용해야함!)
@GeneratedValue
를 사용한다면, id 값이 존재하지 않는 것으로 확인을 할 수 있으나
생성자로 id 를 받아오는 경우에는, id 유무로 isNew 를 판단해야하는데, DB 에 올라가있지도 않은 엔티티에 merge 가 일어남 -> 사이드 이펙트 느낌 물씬
이런 방식으로해서 isNew를 덮어씌워주면 됨.
@Entity
@EntityListeners(AuditingEntityListener.class)
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Item implements Persistable<String> {
@Id
private String id;
@CreatedDate
private LocalDateTime createdDate;
public Item(String id){
this.id = id;
}
@Override
public String getId(){
return id;
}
@Override
public boolean isNew(){
return createdDate == null;
}
}
Jpa Criteria 를 활용해서 하는데, 김영한 개발자님 비추...
ExampleMatcher 와 Prove 로 Example 을 생성하여, 쿼리 조건 만들기!
(QueryDSL 로 해결 가능)
Spring Data Jpa 를 사용해서 조회를 하는데, Entity 말고 특정 값들만 가지고 오고 싶을때!
public interface UsernameOnly {
String getUsername();
}
이렇게 만들어 두고,
<MemberRepository.java> - interface
...
List<Member> findByUsername(@Param("username") String username);
List<UsernameOnly> findProjectionsByUsername(@Param("username") String username);
분명 interface 인데, 알아서 proxy 객체로 생성을 해줌!
이런식으로 지정해주는 것도 가능함!
public class UsernameOnlyDto {
private final String username;
public UsernameOnlyDto(String username) {
this.username = username;
}
public String getUsername() {
return username;
}
}
생성자에서 받아오는 인자의 이름이 중요!! 이름 기반으로 엔티티 필드 찾아감
<MemberRepository.java> interface 에 이와 같이 구현
List<UsernameOnlyDto> findClassProjectionsByUsername(@Param("username") String username);
이래도 똑같이 작동함!! class 가 명시되어 있기에, proxy 객체가 아님
애초에 findByUsername
함수를 만들때, class type 을 지정하도록 할 수 있음
<T> List<T> findCustomByUsername(@Param("username") String username, Class<T> type);
사용 예시
List<UsernameOnlyDto> result = memberRepository.findCustomByUsername("m1", UsernameOnlyDto.class);
덧) join 된 엔티티의 필드들도 같이 가져올 수 있음!!
실무에서는 단순할 때만 사용하고, 복잡해지면 QueryDSL을 사용하자!!
JPQL 문법이 아닌, 실제 SQL 문법으로 적어서 쓸 수 있도록 지원해줌!!
위에서 이야기한 join 된 복합 DTO를 가져오는 것이 좀더 편리하게 가능함!
public interface MemberProjection {
Long getId();
String getUsername();
String getTeamName();
}
@Query(value = "select m.member_id as id, m.username, t.name as teamName " +
"from member m left join team t",
countQuery = "select count(*) from member",
nativeQuery = true)
Page<MemberProjection> findByNativeProjection(Pageable pageable);
역시나 가급적 안씀! JPQL, QueryDSL 로 왠만하면 다 해결하려고 함!!