Spring Data JPA. How to get only a list of IDs from findAll() method

后端 未结 4 1414
小蘑菇
小蘑菇 2020-12-13 18:16

I have a very complicated model. Entity has a lot relationship and so on.

I try to use Spring Data JPA and I prepared a repository.

but when I invoke a met

4条回答
  •  不思量自难忘°
    2020-12-13 18:27

    Unfortunately Projections does not work with specifications. JpaSpecificationExecutor return only a List typed with the aggregated root managed by the repository ( List findAll(Specification var1); )

    An actual workaround is to use Tuple. Example :

        @Override
        public  D findOne(Projections projections, Specification specification, SingleTupleMapper tupleMapper) {
            Tuple tuple = this.getTupleQuery(projections, specification).getSingleResult();
            return tupleMapper.map(tuple);
        }
    
        @Override
        public > List findAll(Projections projections, Specification specification, TupleMapper tupleMapper) {
            List tupleList = this.getTupleQuery(projections, specification).getResultList();
            return tupleMapper.map(tupleList);
        }
    
        private TypedQuery getTupleQuery(Projections projections, Specification specification) {
    
            CriteriaBuilder cb = entityManager.getCriteriaBuilder();
            CriteriaQuery query = cb.createTupleQuery();
    
            Root root = query.from((Class) domainClass);
    
            query.multiselect(projections.project(root));
            query.where(specification.toPredicate(root, query, cb));
    
            return entityManager.createQuery(query);
        }
    

    where Projections is a functional interface for root projection.

    @FunctionalInterface
    public interface Projections {
    
        List> project(Root root);
    
    }
    

    SingleTupleMapper and TupleMapper are used to map the TupleQuery result to the Object you want to return.

    @FunctionalInterface
    public interface SingleTupleMapper {
    
        D map(Tuple tuple);
    }
    
    @FunctionalInterface
    public interface TupleMapper {
    
        List map(List tuples);
    
    }
    

    Example of use :

            Projections userProjections = (root) -> Arrays.asList(
                    root.get(User_.uid).alias(User_.uid.getName()),
                    root.get(User_.active).alias(User_.active.getName()),
                    root.get(User_.userProvider).alias(User_.userProvider.getName()),
                    root.join(User_.profile).get(Profile_.firstName).alias(Profile_.firstName.getName()),
                    root.join(User_.profile).get(Profile_.lastName).alias(Profile_.lastName.getName()),
                    root.join(User_.profile).get(Profile_.picture).alias(Profile_.picture.getName()),
                    root.join(User_.profile).get(Profile_.gender).alias(Profile_.gender.getName())
            );
    
            Specification userSpecification = UserSpecifications.withUid(userUid);
    
            SingleTupleMapper singleMapper = tuple -> {
    
                BasicUserDto basicUserDto = new BasicUserDto();
    
                basicUserDto.setUid(tuple.get(User_.uid.getName(), String.class));
                basicUserDto.setActive(tuple.get(User_.active.getName(), Boolean.class));
                basicUserDto.setUserProvider(tuple.get(User_.userProvider.getName(), UserProvider.class));
                basicUserDto.setFirstName(tuple.get(Profile_.firstName.getName(), String.class));
                basicUserDto.setLastName(tuple.get(Profile_.lastName.getName(), String.class));
                basicUserDto.setPicture(tuple.get(Profile_.picture.getName(), String.class));
                basicUserDto.setGender(tuple.get(Profile_.gender.getName(), Gender.class));
    
                return basicUserDto;
            };
    
            BasicUserDto basicUser = findOne(userProjections, userSpecification, singleMapper);
    

    I hope it helps.

提交回复
热议问题