JPA에서 isDelete=true를 제외하고 검색하는 방법의 종류

haruceki·2024년 9월 11일
0

JPA에서 isDelete=true를 제외하고 검색하는 방법

실제 현업에서는 삭제되는 데이터를 데이터베이스에서 지우지 않는다. isDelete 속성을 true로 바꾸거나 deleteAt, deleteBy 속성으로 관리한다. 그렇다면 삭제된 데이터를 제외하고 검색하려면 어떻게 해야할까?

효율성은 상황에 따라 달라질 수 있으므로 상황에 따라 적합한 방식을 선택하면 된다. JPQL 또는 Criteria API는 유연하고 복잡한 쿼리 작성에 적합하며, specification또는 querydsl은 동적 쿼리가 필요한 경우에 적합하다. @Where 애너테이션은 간단하고 자동화된 필터링이 필요시에 유용하지만 hibernate-specific이다. 쿼리메서드의 경우 가장 간단하고 직관적인 방법으로, 기본적인 조건 검색에 효율적이다.

1. JPQL 또는 Criteria API를 사용하여 쿼리 작성

@Query 애너테이션을 사용하여 JPQL 쿼리를 작성하거나 Criteria API를 사용하여 동적으로 쿼리를 생성한다. 이 방법은 직접 쿼리를 작성하기 때문에 유연하고 성능이 좋을 수 있다.

  • JPQL 예시
public interface HubRepository extends JpaRepository<Hub, Long> {
    @Query("SELECT h FROM Hub h WHERE h.isDelete = false")
    List<Hub> findAllActiveHubs();
}
  • Criteria API 예시
public List<Hub> findAllActiveHubs() {
    CriteriaBuilder cb = entityManager.getCriteriaBuilder();
    CriteriaQuery<Hub> query = cb.createQuery(Hub.class);
    Root<Hub> root = query.from(Hub.class);
    query.select(root).where(cb.equal(root.get("isDelete"), false));
    
    return entityManager.createQuery(query).getResultList();
}

2. 엔티티에 @SQLRestriction 애너테이션 사용 (Hibernate-specific)

Hibernate에서는 @SQLRestriction 애너테이션을 사용하여 특정 조건을 자동으로 추가할 수 있다. 이 방법은 데이터베이스 쿼리에서 isDelete가 false인 레코드만 가져오도록 자동으로 필터링한다. 이 방법은 Hibernate-specific이므로 다른 JPA 구현체에서는 지원되지 않을 수 있다.

import org.hibernate.annotations.Where;

@Entity
@SQLRestriction("is_delete IS FALSE")

출처: https://jaeseo0519.tistory.com/375 [코드를 찢다:티스토리]
public class Hub {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private boolean isDelete;
    
}

3. 스펙 정의 및 사용 (Spring Data JPA)

Spring Data JPA의 Specification 또는 Querydsl을 사용하여 동적으로 쿼리를 작성할 수 있습니다. 이 방법은 복잡한 쿼리를 동적으로 생성할 수 있는 장점이 있습니다.

  • Specification 예시
import org.springframework.data.jpa.domain.Specification;

public class HubSpecifications {
    public static Specification<Hub> isActive() {
        return (root, query, cb) -> cb.equal(root.get("isDelete"), false);
    }
}
  • 사용 예시
public interface HubRepository extends JpaRepository<Hub, Long>, JpaSpecificationExecutor<Hub> {
}

public List<Hub> findAllActiveHubs() {
    return hubRepository.findAll(HubSpecifications.isActive());
}

4. 쿼리 메서드

Spring Data JPA의 쿼리 메서드를 사용하여 조건을 지정할 수 있다. 기본적인 방법이며, 간단한 조건에서는 매우 효율적이다.

public interface HubRepository extends JpaRepository<Hub, Long> {

    List<Hub> findByIsDeleteFalse();
}

@SQLRestriction 사용할 경우, 해당 어노테이션을 무시하고 싶을때 방법

1. nativeQuery 사용

@Query 어노테이션에 nativeQuery = true 속성을 추가하여, SQL을 직접 작성함으로써 @SQLRestriction 조건을 우회할 수 있다.
(@Query를 사용한 JPQL로는 불가능하다.)

@Query(value = "SELECT * FROM delivery_user du WHERE du.user_id = :userId", nativeQuery = true)
Optional<DeliveryUser> findByUserIgnoreIsDelete(@Param("userId") Long userId);

2. EntityManager 사용

EntityManager를 사용하여 커스텀 쿼리를 실행하면, 엔티티에 설정된 @SQLRestriction 조건이 적용되지 않는다.

@Autowired
private EntityManager entityManager;

public DeliveryUser findUserIgnoreDelete(Long userId) {
    String query = "SELECT du FROM DeliveryUser du WHERE du.user.id = :userId";
    return entityManager.createQuery(query, DeliveryUser.class)
                        .setParameter("userId", userId)
                        .getSingleResult();
}

3. 동적 쿼리 사용

Spring Data JPA의 Specification을 사용해 동적으로 조건을 빼거나 추가할 수 있다. 이 경우에도 @Where 조건은 무시된다.

public Optional<DeliveryUser> findUserIgnoreDelete(User user) {
    return deliveryUserRepository.findOne((root, query, cb) -> {
        return cb.equal(root.get("user"), user);
    });
}
profile
희망도 절망도 없이 매일 코딩을 한다.

0개의 댓글