[JPA] 프록시의 동등성 비교법

  • 엔티티의 동등성 비교법
    • 비즈니스 키를 사용해 equals() 메서드를 오버라이딩해야함
  • 프록시와 동등성 비교 문제
    • 단순 원본 엔티티끼리의 비교에서는 IDE 나 외부 라이브러리가 제공한 equals 로 충분하지만..
    • 프록시 객체와의 비교에서는 문제가 발생함
@Entity
public class Member {
    @Id
    private String id;
    private String name;

    public String getName() { return name; }
    public void setName(String name) { this.name = name; }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) return true;
        if (obj == null) return false;
        if (this.getClass() != obj.getClass()) return false;

        Member member = (Member) obj;
        if (name != null ? !name.equals(member.name) : member.name != null) return false;
        return true;
    }

    @Override
    public int hashCode() {
        return name != null ? name.hashCode() : 0;
    }
}
  • 위 코드를 보면..

일단

프록시 객체와 equals 비교 문제

  • JPA 프록시는 원본 엔티티의 대리 객체임.
    • 프록시 객체는 원본 엔티티를 상속받아 구현되기에
    • getClass() 호출시 메서드가 프록시 클래스를 반환할 수 잇음
  • 만약 그렇다면
    • 프록시 객체와 원본 엔티티간의 getClass() 의 비교가 실패할 수 있음.
  • 이러한 문제 때문에
    • equals 메서드를
    • JPA 버디에서 제공하는
      @Override
          public final boolean equals(Object o) {
              if (this == o) return true;
              if (o == null) return false;
              Class<?> oEffectiveClass = o instanceof HibernateProxy ? ((HibernateProxy) o).getHibernateLazyInitializer()
                                                                                           .getPersistentClass() : o.getClass();
              Class<?> thisEffectiveClass = this instanceof HibernateProxy ? ((HibernateProxy) this).getHibernateLazyInitializer()
                                                                                                    .getPersistentClass() : this.getClass();
              if (thisEffectiveClass != oEffectiveClass) return false;
              Member member = (Member) o;
              return getId() != null && Objects.equals(getId(), member.getId());
          }
    • 해당 메서드로 엔티티에서 오버라이딩하여
    • 동등성 비교시
              Class<?> oEffectiveClass = o instanceof HibernateProxy ? ((HibernateProxy) o).getHibernateLazyInitializer()
                                                                                           .getPersistentClass() : o.getClass();
              Class<?> thisEffectiveClass = this instanceof HibernateProxy ? ((HibernateProxy) this).getHibernateLazyInitializer()
                                                                                                    .getPersistentClass() : this.getClass();
              if (thisEffectiveClass != oEffectiveClass) return false;
      • 현재 객체와 비교하는 객체의 실제 클래스를 확인하고
      • 객체가 하이버네이트 구현체의 프록시 객체라면
        • 실제 객체를 들고오도록한다.
      • 이후 두 실 객체를 비교하도록 하는 방법도 있다.

Uploaded by N2T