import com.querydsl.jpa.impl.JPAQueryFactory;
import jakarta.persistence.EntityManager;
import org.springframework.stereotype.Repository;
import study.querydsl.entity.Member;
import java.util.Optional;
import java.util.List;
@Repository
public class MemberJpaRepository {
private final EntityManager em;
private final JPAQueryFactory queryFactory;
public MemberJpaRepository(EntityManager em) {
this.em = em;
this.queryFactory = new JPAQueryFactory(em);
}
public void save(Member member){
em.persist(member);
}
public Optional<Member> findById(Long id){
Member findMember = em.find(Member.class, id);
return Optional.ofNullable(findMember);
}
public List<Member> findAll(){
return em.createQuery("select m from Member m",Member.class)
.getResultList();
}
public List<Member> findByUsername(String username){
return em.createQuery("select m from Member m where m.username = :username",Member.class)
.setParameter("username",username)
.getResultList();
}
}
@Bean
JPAQueryFactory jpaQueryFactory(EntityManager em) {
return new JPAQueryFactory(em);
}
@Data
public class MemberTeamDto {
private Long memberId;
private String username;
private int age;
private Long teamId;
private String teamName;
@QueryProjection
public MemberTeamDto(Long memberId, String username, int age, Long teamId, String teamName) {
this.memberId = memberId;
this.username = username;
this.age = age;
this.teamId = teamId;
this.teamName = teamName;
}
}
Query 중급문법에서 사용한 Builder 사용하기.
public List<MemberTeamDto> searchByBuilder(MemberSearchCond cond){
BooleanBuilder builder = new BooleanBuilder();
if(hasText(cond.getUsername())){
builder.and(member.username.eq(cond.getUsername()));
}
if(hasText(cond.getTeamName())){
builder.and(team.name.eq(cond.getTeamName()));
}
if(cond.getAgeGoe() != null){
builder.and(member.age.goe(cond.getAgeGoe()));
}
return queryFactory
.select(new QMemberTeamDto(
member.id,
member.username,
member.age,
team.id,
team.name
))
.from(member)
.leftJoin(member.team,team)
.where(builder)
.fetch();
}
spring:
profiles:
active: local
그 후 테스트에 resource 디렉토리를 만들고 yml 파일을 복사해서 넣어준 뒤에 위의 부분의 active를 test로 바꿔준다.
@Profile("local") // -> profile이 local인 곳에서만 돌아감.
@Component
@RequiredArgsConstructor
public class InitMember {
private final InitMemberService initMemberService;
@PostConstruct
public void init(){
initMemberService.init();
}
@Component
static class InitMemberService{
@PersistenceContext
EntityManager em;
@Transactional
public void init(){
Team teamA = new Team("teamA");
Team teamB = new Team("teamB");
em.persist(teamA);
em.persist(teamB);
for(int idx = 0; idx <100; idx++){
Team selectTeam = idx%2 == 0 ? teamA : teamB;
em.persist(new Member("member" + idx,idx,selectTeam));
}
}
}
}
결론적으로 @PostConstruct 는 해당 빈의 AOP 적용이 보장되지 않기 때문에 분리해야한다.
참고한 글 : @PostConstruct와 @Transactional 분리 - 인프런 (inflearn.com)