코드 그라데이션

프로젝션 본문

Database/JPQL

프로젝션

완벽한 장면 2023. 8. 29. 11:27

프로젝션

 

1. SELECT m FROM MEMBER m -> 엔티티 프로젝션

JpqlMain

public class JpqlMain {

  public static void main(String[] args) {
    EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
    EntityManager em = emf.createEntityManager();

    EntityTransaction tx = em.getTransaction();
    tx.begin();

    try {
      Member member = new Member();
      member.setUsername("member1");
      member.setAge(10);
      em.persist(member);

      em.flush();
      em.clear(); // 비움

      // 엔티티 프로젝션
      List<Member> result = em.createQuery("select m from Member m", Member.class)
              .getResultList();
      // 여기서 m이 엔티티인데, 그럼 엔티티들이 반환된다.
      // 얘는 영속성 컨텍스트에서 관리되는가?

      // 정답은 바뀌면 관리가 되고, 안 바뀌면 관리가 안 된다.
      Member findMember = result.get(0);
      findMember.setAge(20); // 여기서는 바귐

      tx.commit();
    } catch (Exception e) {
      tx.rollback();
      e.printStackTrace();
    } finally {
      em.close();
    }
    emf.close();
  }

}

 

실행 결

업데이트 쿼리 나갔다.

 

h2도

age가 변경되어 있다.

select 절이 엄청 여러개 나와도 영속성 컨텍스트에 다 걸려서 관리되게 되어 있다.

거기 있는 걸 바꾸면 정상적으로 데이터 반영도 잘 된다.

 

 

2. SELECT m.TEAM FROM MEMBER m -> 엔티티 프로젝션(결과가 멤버와 연관된 팀)

 

public class JpqlMain {

  public static void main(String[] args) {
    EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
    EntityManager em = emf.createEntityManager();

    EntityTransaction tx = em.getTransaction();
    tx.begin();

    try {
      Member member = new Member();
      member.setUsername("member1");
      member.setAge(10);
      em.persist(member);

      em.flush();
      em.clear(); // 비움
      
      // 2. 엔티티 프로젝션 - 팀
      List<Team> result = em.createQuery("select m.team from Member m", Team.class)
              .getResultList();

      tx.commit();
    } catch (Exception e) {
      tx.rollback();
      e.printStackTrace();
    } finally {
      em.close();
    }
    emf.close();
  }

}

 

이거 실행해보면

 

join이 된다. JPQL은 평범하게 생겼어도 SQL에서는 왜냐하면 Team을 찾아야 하므로,

그런데 SQL과 웬만하면 똑같이 써주는 게 바람직하므로, 식은 이렇게 써주는 게 더 낫다.

이렇게 해야 한 눈에 인식이 되니까.

뒤에 경로표현식에서 명시적 조인 / 묵시적 조인에서 자세히 배움.

 

 

3. SELECT m.address FROM Member m -> 임베디드 타입 프로젝션

public class JpqlMain {

  public static void main(String[] args) {
    EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
    EntityManager em = emf.createEntityManager();

    EntityTransaction tx = em.getTransaction();
    tx.begin();

    try {
      Member member = new Member();
      member.setUsername("member1");
      member.setAge(10);
      em.persist(member);

      em.flush();
      em.clear(); // 비움

      // 3. 임베디드 타입 프로젝션
      List<Address> result = em.createQuery("select o.address from Order o", Address.class)
          .getResultList();

      tx.commit();
    } catch (Exception e) {
      tx.rollback();
      e.printStackTrace();
    } finally {
      em.close();
    }
    emf.close();
  }

}

실행한 것 보면

Address 관련된 것만 잘 찾아옴을 확인할 수 있음.

 

주의, 값 타입이 어디 소속인지를 확실하게 명기해줘야 함.

 

 

 

4. SELECT m.username, m.age FROM Member m -> 스칼라 타입 프로젝션

public class JpqlMain {

  public static void main(String[] args) {
    EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
    EntityManager em = emf.createEntityManager();

    EntityTransaction tx = em.getTransaction();
    tx.begin();

    try {
      Member member = new Member();
      member.setUsername("member1");
      member.setAge(10);
      em.persist(member);

      em.flush();
      em.clear(); // 비움

      // 4. 스칼라 타입 프로젝션
      em.createQuery("select m.username, m.age from Member m")
          .getResultList();

      tx.commit();
    } catch (Exception e) {
      tx.rollback();
      e.printStackTrace();
    } finally {
      em.close();
    }
    emf.close();
  }

}

 

 

실행 결과

이렇게 원하는 값만 조회 가능

 

참고. DISTINCT 로 중복 제거


 

그런데, 타입이 다른데 어떻게 가져와야 하느냐에 대한 고민

그러한 방법

프로젝션 - 여러 값 조회 방법

 

1. Query 타입으로 조회

public class JpqlMain {

  public static void main(String[] args) {
    EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
    EntityManager em = emf.createEntityManager();

    EntityTransaction tx = em.getTransaction();
    tx.begin();

    try {
      Member member = new Member();
      member.setUsername("member1");
      member.setAge(10);
      em.persist(member);

      em.flush();
      em.clear(); // 비움

      // 1) Query 타입으로 조회
      List resultList = em.createQuery("select m.username, m.age from Member m")
          .getResultList();
      
      Object o = resultList.get(0);
      Object[] result = (Object[]) o;
      System.out.println("username : " + result[0]);
      System.out.println("age : " + result[1]);

      tx.commit();
    } catch (Exception e) {
      tx.rollback();
      e.printStackTrace();
    } finally {
      em.close();
    }
    emf.close();
  }

}

 

실행해보면 결과는

 

2. Object[ ] 타입으로 조회

// 2) Object[] 타입으로 조회
List<Object[]> resultList = em.createQuery("select m.username, m.age from Member m")
    .getResultList();

Object[] result = resultList.get(0);
System.out.println("username : " + result[0]);
System.out.println("age : " + result[1]);

 

 

3. new 명령어로 조회(가장 깔끔)

일단 MemberDto 만들어놓고

public class MemberDto {
  
  private String username;
  private int age;

  public String getUsername() {
    return username;
  }

  public void setUsername(String username) {
    this.username = username;
  }

  public int getAge() {
    return age;
  }

  public void setAge(int age) {
    this.age = age;
  }
}

 

 

밑줄 친 부분은 나중에 QueryDSL 을 쓰면 다 극복이 되는 부분이다.

자바 코르로 짤 때는 이 패키지명을 모두 임포트 해서 쓸 수가 있다.

지금은 문자이기 때문에, 다 적어줘야 한다.

728x90

'Database > JPQL' 카테고리의 다른 글

서브 쿼리  (0) 2023.08.31
조인 (2) - ON 절  (0) 2023.08.30
조인 (1) - 내부 조인, 외부 조인, 세타 조인  (0) 2023.08.30
페이징 API  (0) 2023.08.30
JPQL 소개  (0) 2023.08.28
Comments