简体   繁体   中英

How to query only limited columns in Hibernate, and map them to a given POJO?

My project involves using GraphQL within a Spring Boot app. For demonstration purposes, here is my GraphQL schema:

type Company{
  name: String,
  parentOrganization: String,
  flag:Int
}

I'm still learning Spring Boot and JPA, so I use spring-boot-starter-data-jpa for all the JPA, Hibernate, etc.

My problem is, when someone queries only for name and organization , Hibernate queries for all the columns and GraphQL picks the columns requested.

@Repository
@Transactional
public interface CompanyRepository extends JpaRepository<Company,Long> {

}

The above code doesn't really give me any flexibility in limiting the columns that are queried. I've tried using Hibernate's Criteria API as well, but whichever way I go, I get this error:

Unable to locate appropriate constructor on class [packagee.entity.company]. Expected arguments are: java.lang.String, java.lang.String [select new package.entity.Company(generatedAlias0.company, generatedAlias0.organization) from package.entity.Company as generatedAlias0]

Below is the code for my Criteria implementation:

    public static List<Company> get(EntityManager em, List<String> fieldsAsked){
        CriteriaBuilder cb = em.getCriteriaBuilder();
        CriteriaQuery<Company> cq = cb.createQuery(Company.class);

        Root<Company> root = cq.from(Company.class);
        List<Selection<?>> selectionList = new LinkedList<Selection<?>>();

        for(String name: fieldsAsked){
            selectionList.add(root.get(name));
        }
        cq.multiselect(selectionList);

        return em.createQuery(cq).getResultList();
    }

How do I get limited columns from Hibernate? I've seen many answers online that ask to make appropriate constructor in the entity class, but that's not really possible for me because my entity parameters are mostly Strings and I cant make constructors for all the permutations possible (because I'm using GraphQL, the control of what to query really goes to the end user of my project).

What should I do? Thanks in advance!

Solution 1:

You can create a new DTO class which will be returned by your query.

The DTO class:

public class CompanyDTO(){
   //fields,constructor
}

And in the repository:

 @Query(value = "SELECT new com.example.dto.companyDTO" +
        "(c.name,c.parentOrganization)" +
        " FROM Company c")
    List<CompanyDTO>findCompanySelectedColumns(PageRequest pageable);

Solution 2(clean solution):

You can use interface. Do not implement the interface .

interface customCustomer{
   String getName();
   String getParentOrganization();
}

In repository:

List<CustomCustomer>findAllByNameAndParentOrganization();

What you want to do is not really possible with Hibernate directly, but you can checkoutBlaze-Persistence Entity-Views which also has a GraphQL integration that supports exactly what you are looking for. See https://persistence.blazebit.com/documentation/1.6/entity-view/manual/en_US/#graphql-integration

Here is a sample project that shows how you can use this: https://github.com/Blazebit/blaze-persistence/tree/master/examples/spring-data-graphql

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM