programing

스프링 데이터 - 값이 null인 경우 매개 변수 무시

yellowcard 2023. 3. 6. 20:58
반응형

스프링 데이터 - 값이 null인 경우 매개 변수 무시

2개의 파라미터를 갖는 스프링 데이터 저장소 인터페이스를 원합니다.다음과 같은 동작을 할 수 있는 방법이 있습니까?

MyObject findByParameterOneAndParameterTwo( String parameterOne, String parameterTwo);

두 파라미터 모두 값이 있으면 정상적으로 동작하고 두 값에 대해 "AND"를 수행했으면 합니다.

예를 들어 두 번째 파라미터가 null인 경우 ParameterOne에서만 검색합니다.

좋은 의견이라도 있나?

저장소 메서드의 이름을 붙이는 것이 가능한지는 잘 모르겠지만 다음을 사용할 수 있습니다.@Query맘에 들다

(:parameterOne is null or parameter1 = :parameterOne) and (:parameterTwo is null or parameter2 = :parameterTwo)

이 솔루션에는 스프링 데이터 JPA의 Query By Example 기능이 없습니다.이를 활용하여 이 문제를 해결할 수 있습니다.사용자 지정 쿼리 및 쿼리 작성기는 필요하지 않습니다.

이 스프링 데이터 쿼리:

ExampleMatcher matcher = ExampleMatcher.matching().withIgnoreNullValues();
Example<MyObject> exampleQuery = Example.of(new MyObject("foo", null), matcher);
List<MyObject> results = repository.findAll(exampleQuery);

다음과 같은 쿼리를 생성합니다.

select * 
from myObject 
where parameter1 = "foo"

다음과 같은 경우:

ExampleMatcher matcher = ExampleMatcher.matching().withIgnoreNullValues();
Example<MyObject> exampleQuery = Example.of(new MyObject("foo", "bar"), matcher);
List<MyObject> results = repository.findAll(exampleQuery);

수율:

select * 
from myObject 
where parameter1 = "foo"
and parameter2 = "bar"

멋있다!

주의: 고객님이 해야 할 일은Repository인터페이스 추가QueryByExample인터페이스입니다.이 작업은 다음 중 하나를 확장하여 수행할 수 있습니다.QueryByExample직접 인터페이스 또는 인터폴리티를 통해JpaRepository:

public interface MyObjectRepository extends JpaRepository<MyObject, Long> {}

현시점에서는 이것은 불가능합니다.Spring-data-jpa.

이 있습니다.JIRA 아직 조사 중인 이 건에 관한 티켓Spring팀.

여기에 이미지 설명 입력

그러나 회피책이 필요한 경우 간단한 기준 쿼리 예를 확인할 수 있습니다.


업데이트:

상기 티켓은 종료되었으며 스프링 팀은 복잡성이 수반되고 Query by Example이 실현 가능한 옵션이기 때문에 이 기능의 실장에 관심이 없습니다.이 댓글 좀 보세요.

여기에 이미지 설명 입력

그 방법은 다음과 같습니다.

@Query("SELECT c FROM Customer c WHERE (:name is null or c.name = :name) and (:email is null"
      + " or c.email = :email)")
    List<Customer> findCustomerByNameAndEmail(@Param("name") String name, @Param("email") String email);

Kolobok을 먹어봐

@FindWithOptionalParams
Iterable<MyObject> findByParameterOneAndParameterTwo( String parameterOne, String parameterTwo);
  1. JPA 쿼리
@Query("SELECT c FROM Customer c WHERE (:name is null or c.name = :name)")
  1. JPA 쿼리(nativeQuery = true)
@Query(nativeQuery = true, "SELECT id, name FROM Customer WHERE (false = :nameOn OR name = :name)")
List<Entity> findAll(@Param(value = "nameOn") Boolean nameOn, @Param(value = "name ") String name);
  • nativeQuery에서 이름이 null인 경우 이름을 EMTEMY 문자열로 변경해야 합니다.

3개의 클래스를 사용하여 Criteria Builder를 사용했습니다.

JPA를 사용한 저장소 인터페이스

 @Repository
 public interface NotificationRepository extends JpaRepository<Notification, 
 Long>, NotificationRepositoryCustom {
}

커스텀 인터페이스

public interface NotificationRepositoryCustom {

    List<Notification> findNotificationByCustomerIdAndRecipientAndNotificationAckStatusAndNotificationRequestChannel
            (Long customerId, String userId, List<String> status, List<String> channels);
}

NotificationRepositoryCustom 구현

public class NotificationRepositoryCustomImpl implements NotificationRepositoryCustom {

    @PersistenceContext
    private EntityManager entityManager;

    @Override
    public List<Notification> findNotificationByCustomerIdAndRecipientAndNotificationAckStatusAndNotificationRequestChannel(Long customerId, String userId, List<String> status, List<String> channels) {

        CriteriaBuilder cb = entityManager.getCriteriaBuilder();
        CriteriaQuery<Notification> query = cb.createQuery(Notification.class);
        Root<Notification> notification = query.from(Notification.class);


        List<Predicate> predicates = new ArrayList<Predicate>();
        if (userId != null)
            predicates.add(cb.equal(notification.get("recipient"), userId));
        if (customerId != null)
            predicates.add(cb.equal(notification.get("customerId"), customerId));
        if (CollectionUtils.isNotEmpty(status))
            predicates.add(notification.get("notificationAckStatus").get("ackStatusCode").in(status));
        if (CollectionUtils.isNotEmpty(channels))
            predicates.add(notification.get("notificationRequestChannel").get("notificationChannel").get("channelCode").in(channels));


        if (!predicates.isEmpty()) {
            query
                    .select(notification)
                    .where(cb.and(
                            predicates.toArray(new Predicate[predicates.size()])));

        }
        return entityManager.createQuery(query).getResultList();
    }
}

봄/J에 처음 왔어요.PA 공간,

'예제별 쿼리' 사용

( in seviceImp )를 사용하고 있습니다.아래의 인수는 모두 옵션입니다./사용자의 선택에 따라 다릅니다.

`
  .
    if (!firstName.isEmpty() ) {
    staff.setFirstName(firstName);
    }



    if (!lastName.isEmpty() ) {
    staff.setLastName(lastName);
    }

    if (!ptAadhar.isEmpty() ) {
        patient.setPtAadhar(ptAadhar);
    }

    if (!Cell.isEmpty() ) {
        staff.setCell(Cell);
    }


      Example<StaffEntity> example = Example.of(staff);  

      List<StaffEntity> staffList =staffRepository.findAll(example);
       .

이거 드셔보세요.

      @Query(value = "SELECT pr FROM ABCTable pr " +
        "WHERE((pr.parameterOne = :parameterOne) or (pr.parameterOne = null and :parameterOne = null)) and 
        ((pr.parameterTwo = :parameterTwo) or (pr.parameterTwo = null and :parameterTwo = null)) ")
      List<PaymentRequest> getSomething (@Param("parameterOne") String parameterOne,
                                             @Param("parameterTwo") String parameterTwo);

파라미터에 늘 또는 빈 값이 있는지 확인하려면 다음과 같이 해야 합니다.

@Query("SELECT t FROM Test t WHERE (:parameterOne IS NULL) OR (:parameterOne = '')");

이 문제를 해결하려면 Spring JPA Data Specification을 사용하는 것이 좋습니다.

이 솔루션은 모든 데이터 유형에 대해 작동하며 모든 DB 기능(더 큰 기능/작은 기능/좋음/같음/또는 없음/등)을 허용합니다.

저는 개인적으로 비즈니스 로직/기준 빌더를 여기에 캡슐화하면 서비스 코드를 훨씬 더 쉽게 읽을 수 있다는 것을 알게 됩니다. 특히 사양 방법에 좋은 이름을 붙이면 더욱 그렇습니다.또한 공개 메서드를 사용하여 사양 코드를 보다 쉽게 읽을 수 있도록 개인 메서드를 사용할 수도 있습니다.

OP의 예에서는 다음 메서드로 클래스를 만듭니다.

public static Specification<Entity> equalsParameterOne(String parameterOne){
    //If the specification is null it will be excluded from the SQL and ignored
    if(parameterOne == null || parameterOne.length = 0) return null;
         
    return (root, query, cb) -> cb.equal(root.get("fieldOne"), parameterOne);
}

public static Specification<Entity> equalsParameterTwo(String parameterTwo){
    //If the specification is null it will be excluded from the SQL and ignored
    if(parameterTwo== null || parameterTwo.length = 0) return null;
         
    return (root, query, cb) -> cb.equal(root.get("fieldTwo"), parameterTwo);
}

다음으로 jpaRepo를 사용하는 서비스 코드에서 다음과 같이 findAll()과 함께 사용할 수 있습니다.

//Be careful with your parenthesis
Specification<Entity> customDynamicSpecs = 
Specification
.where(equalsParameterOne(criteria.getParamOne()))  
.and(equalsParameterTwo(criteria.getParamTwo()));
//.or().not()
//... as many as you want.

//findAll() can take Pageable or Sort as 2nd argument for extra functionality.
repo.findAll(customDynamicSpecs);

이 작업을 수행하려면 repo extends JpaSpecification을 선언해야 합니다.이그제큐티브나 스태틱한 Import는, 어느 누구라도 만족할 수 있는 것보다 몇개인가 더 많이 실시합니다.하지만 다시 말씀드리지만, 제게는 판독 가능한 코드가 승리합니다.

너도 그럴 수 있어.

저장소:

`MyObject findByParameterOneAndParameterTwo( String parameterOne, String parameterTwo);`

null parameterTwo를 전달하면 생성된 JPQL에 IS NULL 조건이 포함됩니다.

`myobject0_.parameterTwo is null`

::repository.findByParameterOneAndParameterTwo("D", null);

참고 자료: https://www.baeldung.com/spring-data-jpa-null-parameters#query-methods

Repo를 별도의 클래스로 사용할 수 있을지 모르겠지만 String Builder append 쿼리를 옵션 파라미터와 함께 사용할 수 있습니다.이거면 될 거야

 StringBuilder queryBuilder = new StringBuilder();
    queryBuilder.append("select p.name from personDemographic p "); 
    Boolean flag = true;
    if(parameterOne != null){
      if(flag){
          queryBuilder.append("where condition...");
            flag=false;
        } 
      }
    if(parameterOne != null){
    if(flag){
     queryBuilder.append("where condition...");
     flag = false;
    }else{
      queryBuilder.append("and condition...");
    }
   Query query = entityManager.createQuery(queryBuilder.toString());

언급URL : https://stackoverflow.com/questions/43780226/spring-data-ignore-parameter-if-it-has-a-null-value

반응형