且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

用 QuerydslJpaPredicateExecutor 替换已弃用的 QuerydslJpaRepository 失败

更新时间:2023-02-19 14:12:10

使用 Spring Boot 2.1.1 以下解决方案可能会对您有所帮助.关键是扩展JpaRepositoryFactory 并覆盖方法getRepositoryFragments(RepositoryMetadata metadata).在这种方法中,您可以为任何自定义存储库提供基本(或更具体的片段)实现,每个扩展存储库都应采用这些实现.

With Spring Boot 2.1.1 the following solution may help you. The key is to extend JpaRepositoryFactory and override the method getRepositoryFragments(RepositoryMetadata metadata). In this method you can provide base (or more specific fragment) implementations for any custom repository which should be taken for every extending repository.

让我给你举个例子:

QueryableReadRepository:

@NoRepositoryBean
public interface QueryableReadRepository<T> extends Repository<T, String> {

  List<T> findAll(Predicate predicate);

  List<T> findAll(Sort sort);

  List<T> findAll(Predicate predicate, Sort sort);

  List<T> findAll(OrderSpecifier<?>... orders);

  List<T> findAll(Predicate predicate, OrderSpecifier<?>... orders);

  Page<T> findAll(Pageable page);

  Page<T> findAll(Predicate predicate, Pageable page);

  Optional<T> findOne(Predicate predicate);

  boolean exists(Predicate predicate);
}

以下界面结合了不同的存储库.

The following interface combines different repositories.

数据存储库:

@NoRepositoryBean
public interface DataRepository<T>
    extends CrudRepository<T, String>, QueryableReadRepository<T> {
}

现在您的特定域存储库可以从 DataRepository 扩展:

Now your specific domain repos can extend from DataRepository:

@Repository
public interface UserRepository extends DataRepository<UserEntity> {

}

QueryableReadRepositoryImpl:

@Transactional
public class QueryableReadRepositoryImpl<T> extends QuerydslJpaPredicateExecutor<T>
    implements QueryableReadRepository<T> {

  private static final EntityPathResolver resolver = SimpleEntityPathResolver.INSTANCE;

  private final EntityPath<T> path;
  private final PathBuilder<T> builder;
  private final Querydsl querydsl;

  public QueryableReadRepositoryImpl(JpaEntityInformation<T, ?> entityInformation,
      EntityManager entityManager) {
    super(entityInformation, entityManager, resolver, null);
    this.path = resolver.createPath(entityInformation.getJavaType());
    this.builder = new PathBuilder<T>(path.getType(), path.getMetadata());
    this.querydsl = new Querydsl(entityManager, builder);
  }

  @Override
  public Optional<T> findOne(Predicate predicate) {
    return super.findOne(predicate);
  }

  @Override
  public List<T> findAll(OrderSpecifier<?>... orders) {
    return super.findAll(orders);
  }

  @Override
  public List<T> findAll(Predicate predicate, Sort sort) {
    return executeSorted(createQuery(predicate).select(path), sort);
  }

  @Override
  public Page<T> findAll(Predicate predicate, Pageable pageable) {
    return super.findAll(predicate, pageable);
  }

  @Override
  public List<T> findAll(Predicate predicate) {
    return super.findAll(predicate);
  }

  public List<T> findAll(Sort sort) {
    return executeSorted(createQuery().select(path), sort);
  }

  @Override
  public Page<T> findAll(Pageable pageable) {
    final JPQLQuery<?> countQuery = createCountQuery();
    JPQLQuery<T> query = querydsl.applyPagination(pageable, createQuery().select(path));

    return PageableExecutionUtils.getPage(
        query.distinct().fetch(), 
        pageable,
        countQuery::fetchCount);
  }

  private List<T> executeSorted(JPQLQuery<T> query, Sort sort) {
    return querydsl.applySorting(sort, query).distinct().fetch();
  }
}

CustomRepositoryFactoryBean:

public class CustomRepositoryFactoryBean<T extends Repository<S, I>, S, I>
    extends JpaRepositoryFactoryBean<T, S, I> {

  public CustomRepositoryFactoryBean(Class<? extends T> repositoryInterface) {
    super(repositoryInterface);
  }

  protected RepositoryFactorySupport createRepositoryFactory(EntityManager entityManager) {
    return new CustomRepositoryFactory(entityManager);
  }

CustomRepositoryFactory:

public class CustomRepositoryFactory extends JpaRepositoryFactory {

  private final EntityManager entityManager;

  public CustomRepositoryFactory(EntityManager entityManager) {
    super(entityManager);
    this.entityManager = entityManager;
  }

  @Override
  protected RepositoryFragments getRepositoryFragments(RepositoryMetadata metadata) {
    RepositoryFragments fragments = super.getRepositoryFragments(metadata);

    if (QueryableReadRepository.class.isAssignableFrom(
        metadata.getRepositoryInterface())) {

      JpaEntityInformation<?, Serializable> entityInformation = 
          getEntityInformation(metadata.getDomainType());

      Object queryableFragment = getTargetRepositoryViaReflection(
          QueryableReadRepositoryImpl.class, entityInformation, entityManager);

      fragments = fragments.append(RepositoryFragment.implemented(queryableFragment));
    }

    return fragments;
  }

主类:

@EnableJpaRepositories(repositoryFactoryBeanClass = CustomRepositoryFactoryBean.class)
public class App {
}

这样做的好处是您只需为自定义存储库提供一个(片段)实现.基本存储库实现仍然是 Spring 的默认实现.该示例提供了一个新的存储库,但您也可以在 CustomRepositoryFactory

This has the advantage that you provide only one (fragment) implementation for a custom repo. The base repository implementation is still Spring's default implementation. The example provided a new repo but you can probably also just override the default implementation of QuerydslPredicateExecutor in CustomRepositoryFactory