How do I write a JPA query to populate a data tran

2019-05-31 02:39发布

问题:

We’re using Java 6, JPA 2.1, and Hibernate 4.3.6.Final. I have the below code that finds our Organization objects …

    final CriteriaBuilder builder = entityManager.getCriteriaBuilder();
    final CriteriaQuery<Organization> criteria = builder.createQuery(Organization.class);
    final Root<Organization> root = criteria.from(Organization.class);

    final CriteriaQuery query = buildCriteriaQuery(builder, criteria, root, country, state, organizationTypes, parentOrg, zipCode);
    final TypedQuery<Organization> typedQuery = entityManager.createQuery(query);
    if (page != null && pageSize != null)
    {
        int first = (page - 1) * pageSize;
        typedQuery.setFirstResult(first);
        typedQuery.setMaxResults(pageSize);
    }   // if
    return typedQuery.getResultList();

These Organization objects are very data-intensive objects. We have a data transfer object, OrganizationDto, which only contains a subset of the fields of Organization. Is there a way to configure the above to populate the OrganizationDto objects instead of the Organization objects? What I would like to avoid is getting the result set and then writing a for loop to go through all of it and create all the data transfer objects. It would be great if the query could somehow just populate these data transfer objects right away.

回答1:

There are a few examples of what is called a constructor expression in the JPA 2.1 specification that allow the query to use any pojo's constructor to return instances. The constructor must take the select list as parameters. One the example in the spec written using JPQL:

"SELECT NEW com.acme.example.CustomerDetails(c.id, c.status, o.quantity)
FROM Customer c JOIN c.orders o
WHERE o.quantity > 100"

would be created with a type query as:

CriteriaQuery<CustomerDetails> q =
cb.createQuery(CustomerDetails.class);
Root<Customer> c = q.from(Customer.class);
Join<Customer, Order> o = c.join(Customer_.orders);
q.where(cb.gt(o.get(Order_.quantity), 100));
q.select(cb.construct(CustomerDetails.class,
 c.get(Customer_.id),
 c.get(Customer_.status),
 o.get(Order_.quantity)));

Assuming a constructor for CustomerDetail exists to take in the ID, status and quantity fields, then the query would return these instances instead of Entities.