Query by Spec

Query by Spec (QBS) 提供了 QueryBySpecExecutor<T> 包含了許多查詢方法:

public interface QueryBySpecExecutor<T> {

  List<T> findBySpec(Object spec);
  
  List<T> findBySpec(Object spec, Sort sort);
  
  Page<T> findBySpec(Object spec, Pageable pageable);
  
  // … more functionality omitted.
}

只要在原本的 repository interface 中去繼承 QueryBySpecExecutor<T> 就可以直接使用了:

public interface PersonRepository 
  extends JpaRepository<Person, Long>, QueryBySpecExecutor<Person> {
  ...
}

@Service
public class PersonService {

  @Autowired PersonRepository personRepository;

  public List<Person> findPeople(PersonCriteria criteria) {
    return personRepository.findBySpec(criteria);
  }
}

Customize Base Repository

在配置的過程中, QBS 會自動配置 Spring Data JPA 的 Base Repository, 預設的實作為 DefaultQueryBySpecExecutor

由於 Java 只能單一繼承, 為了應用程式可以保留原有的 Parent Base Repository, QBS 還多提供了 QueryBySpecExecutorAdapter 擴展點

你的應用程式可以視情況選擇繼承 DefaultQueryBySpecExecutor 或實作 QueryBySpecExecutorAdapter 去客製化 Base Repository, 如:

class MyRepositoryImpl<T, ID> extends SimpleJpaRepository<T, ID>
  implements QueryBySpecExecutorAdapter<T> {

  @Setter
  @Getter
  private SpecMapper specMapper;

  private final EntityManager entityManager;

  MyRepositoryImpl(JpaEntityInformation entityInformation,
                          EntityManager entityManager) {
    super(entityInformation, entityManager);

    // Keep the EntityManager around to used from the newly introduced methods.
    this.entityManager = entityManager;
  }

  @Override
  public Class<T> getDomainClass() {
    return super.getDomainClass();
  }
  
  @Transactional
  public <S extends T> S mySave(S entity) {
    // implementation goes here
  }
}

並且透過 properties 中的 spec.mapper.repository-base-class 設定成自定義的 base repository 的 fulll package name, 如:

spec:
  mapper:
    repository-base-class: com.example.MyRepositoryImpl
Last modified March 10, 2025: docs: fix link (d9ad177)