Spring Data JPA Specification to Select Specific Columns

23,552

Solution 1

The current spring data jpa specification executor is limited to criteria in the where clause, so you can't change the selected columns, it's implicitely limited to full entities only (take a look at JpaSpecificationExecutor interface documentation). You'll have to go with a custom repository implementation, or move to named queries-

Spring Data JPA and Querydsl to fetch subset of columns using bean/constructor projection

Solution 2

I tried this, but it returns the entire object all the time.

This method returns single entity matching given specification. Please check here

According to my understanding this is the correct way. U can access the properties of the entity as normal (Eg. MyInfo.getIdProperty())

Solution 3

Specifications are abstractions over where clauses. Due to the design of the JPA criteria API you can all kinds of stuff in Specification but the behaviour of any side effect apart from declaring a where clause is undefined.

If you want to control the select list you can either use query derivation with projections and the very limited query support or construct complete custom queries in a custom method.

Share:
23,552
Chinmay
Author by

Chinmay

Updated on March 14, 2020

Comments

  • Chinmay
    Chinmay about 4 years

    We can select specific columns by writing custom @Query methods in our Repository Interface. However, I don't want to write so many methods for different properties.

    I tried this, but it returns the entire object all the time.

    public class MySpecifications {
    
        public static Specification<MyInfo> propertiesWithId(final String[] properties, final Object id, final String idProperty)
        {
    
            return new Specification<MyInfo>() {
    
                @Override
                public Predicate toPredicate(Root<MyInfo> root,
                        CriteriaQuery<?> query, CriteriaBuilder cb) {
    
                    query = cb.createTupleQuery(); //tried cb.createQuery(MyInfo.class); as well
    
                    List<Selection<? extends Object>> selectionList = new ArrayList<Selection<? extends Object>>();
    
                    for (String property : properties) {
    
                        Selection<? extends Object> selection = root.get(property);
    
                        selectionList.add(selection);
                    }
    
                    return query.multiselect(selectionList).where(cb.equal(root.get(idProperty), id)).getRestriction();
                }
    
            };
        }
    }
    

    used as:

    MyInfo findOne(Specification(properties,idValue, idProperty));
    

    Is this the correct way? Where is the mistake?