Spring Data JPA.如何从findAll()方法中仅获取ID列表

use*_*654 27 spring specifications criteria-api spring-data-jpa

我有一个非常复杂的模型.实体有很多关系,等等.

我尝试使用Spring Data JPA并准备了一个存储库.

但是当我调用metod findAll()时,对象a的规范有一个性能问题,因为对象非常大.我知道,因为当我调用这样的方法时:

@Query(value = "select id, name from Customer ")
List<Object[]> myFindCustomerIds();
Run Code Online (Sandbox Code Playgroud)

我的表现没有任何问题.

但是当我调用时

List<Customer> findAll(); 
Run Code Online (Sandbox Code Playgroud)

我的表现存在很大问题.

问题是我需要使用Specifications for Customer调用findAll方法,这就是为什么我不能使用返回对象数组列表的方法.

如何编写方法来查找具有Customer实体规范但仅返回ID的所有客户.

像这样:

List<Long> findAll(Specification<Customer> spec);
Run Code Online (Sandbox Code Playgroud)
  • 我不能在这种情况下使用分页.

请帮忙.

eav*_*eav 30

为什么不使用@Query注释?

id

我看到的唯一缺点是当属性@Query发生变化时,但由于这是一个非常常见的名称而且不太可能改变(id =主键),这应该没问题.

  • 或者只是 `@Query("从 #{#entityName} 选择 id")` (4认同)
  • 它符合规范吗? (2认同)

Ond*_*zek 18

Spring Data使用Projections现在支持这一点:

interface SparseCustomer {  

  String getId(); 

  String getName();  
}
Run Code Online (Sandbox Code Playgroud)

比在您的Customer存储库中

List<SparseCustomer> findAll(Specification<Customer> spec);
Run Code Online (Sandbox Code Playgroud)

编辑:
正如Radouane ROUFID预测的那样,规格目前不适用于bug.

但是你可以使用规范与投影库来解决这个Spring Data Jpa缺陷.

  • 这实际上适用于这个用例吗?似乎 java 无法区分此方法和由存储库扩展的 JpaSpecificationExecutor&lt;OriginalEntity&gt; 中的原始方法,我不知道改用哪个名称来代替该方法。 (2认同)

use*_*654 9

我解决了这个问题.

(因此我们将只有一个带有id和名称的稀疏Customer对象)

定义自己的存储库:

public interface SparseCustomerRepository {
    List<Customer> findAllWithNameOnly(Specification<Customer> spec);
}
Run Code Online (Sandbox Code Playgroud)

和实现(记住后缀 - 默认为Impl)

@Service
public class SparseCustomerRepositoryImpl implements SparseCustomerRepository {
    private final EntityManager entityManager;

    @Autowired
    public SparseCustomerRepositoryImpl(EntityManager entityManager) {
        this.entityManager = entityManager;
    }

    @Override
    public List<Customer> findAllWithNameOnly(Specification<Customer> spec) {
        CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
        CriteriaQuery<Tuple> tupleQuery = criteriaBuilder.createTupleQuery();
        Root<Customer> root = tupleQuery.from(Customer.class);
        tupleQuery.multiselect(getSelection(root, Customer_.id),
                getSelection(root, Customer_.name));
        if (spec != null) {
            tupleQuery.where(spec.toPredicate(root, tupleQuery, criteriaBuilder));
        }

        List<Tuple> CustomerNames = entityManager.createQuery(tupleQuery).getResultList();
        return createEntitiesFromTuples(CustomerNames);
    }

    private Selection<?> getSelection(Root<Customer> root,
            SingularAttribute<Customer, ?> attribute) {
        return root.get(attribute).alias(attribute.getName());
    }

    private List<Customer> createEntitiesFromTuples(List<Tuple> CustomerNames) {
        List<Customer> customers = new ArrayList<>();
        for (Tuple customer : CustomerNames) {
            Customer c = new Customer();
            c.setId(customer.get(Customer_.id.getName(), Long.class));
            c.setName(customer.get(Customer_.name.getName(), String.class));
            c.add(customer);
        }
        return customers;
    }
}
Run Code Online (Sandbox Code Playgroud)