본문 바로가기

Back-End/JPA

14장. JPA 컬렉션과 부가기능

하이버네이트는 엔티티를 영속 상태로 만들 때 컬렉션 필드를 hibernate 에서 준비한 collection으로 감싸서 사용한다. 예제를 살펴보자

 

Team team = new Team();

// before persist
Sysout(team.getMembers().getClass()); //java.util.ArrayLists

em.persist(team);

// after persist
Sysout(team.getMembers().getClass()); // org.hibernate.collection.internal.PersistentBag

결과를 보면 영속 상태로 변경된 후에 hibernate가 제공하는 PersistentBag로 변경되었다. 원본 컬렉션을 감싸고 있어서 레퍼 컬렉션이라고 부르기도 한다. 이때문에 즉시 초기화해서 사용하는 것을 권장한다.

Collection<Member> members = Lists.newArrayList();

@OrderBy

@OrderColumn 은 관리차원이나 등등의 이유로 실무에서 거의 사용되지 않는다. 대신 @OrderBy는 데이터베이스의 ORDER BY 절을 사용해서 컬렉션을 정렬한다.

@Entity
public class Team {

    @Id
    private String id;

    @OneToMany
    @JoinColumn
    @OrderBy("username desc, id asc")
    private Collection<Member> members = Lists.newArrayList();
}

해당 멤버를 쓸 때 sql 문 로그를 보면 order by m.memer_name desc, m.idd ASC 이런식으로 찍히는걸 확인할 수 있다.

참고로 hibernate에서 set은 순서를 지키기 우이해서 HashSet 대신에 LinkedHashSet을 내부에서 사용한다.

 

@Converter

컨버터를 사용하면 엔티티의 데이터를 변환해서 데이터베이스에 저장할 수 있다.

@Entity
public class Member {

	//...
    
	@Converter(converter=BooleanToYNNConverter.class)
    private boolean vip;
}

 

public class BooleanToYNConverter implements AttributeConverter<Boolean, String> {

    @Override
    public String convertToDatabaseColumn(Boolean attribute) {
        return (attribute != null && attribute) ? "Y" : "N";
    }


    @Override
    public Boolean convertToEntityAttribute(String dbData) {
        return "Y".equals(dbData);
    }
}

리스너

모든 엔티티를 대상으로 언제 어떤 사용자가 삭제를 요청했는지 모두 로그로 남경야 하는 요구사항이 있는 경우 어떻게 할것인가? 모든 비즈니스 로직을 찾을것인가? 이는 너무나도 비효율적이다. 즉, JPA 리스너 기능을 통해 엔티티의 생명주기에 따른 이벤트를 처리할 수 있다.

이벤트 적용 위치는 3가지가 있다.

  1. 엔티티에 직접 등록해서 사용하는 법

  2. 별도의 리스너 등록
  3. 기본 리스너 사용
@Entity
public class Member implements Serializable {

    @PrePersist
    public void prePersist() {
        System.out.println("prePersist");
    }
}