3

JPQL makes this kind of change very easy:

Select o from Orders as o where....

Select o.id from Orders as o where....

But in Criteria Query:

CriteriaBuilder builder = kem.getCriteriaBuilder();
CriteriaQuery<Orders> query = builder.createQuery(Orders.class);
Root<Order> orders= query.from(Orders.class);
query.select(orders);
....

It looks that the select item is defined by builder.createQuery(Order.class) already without any flexibility.

I know we can use Tuple.class, but other than like is there any better way to just extra id(just one field) from a complicated query? Without such feature criteria query becomase very lack of flexibility.

manish
  • 19,695
  • 5
  • 67
  • 91
Dreamer
  • 7,333
  • 24
  • 99
  • 179
  • I think you could query for a Tuple object as per this question: http://stackoverflow.com/questions/12618489/jpa-criteria-api-select-only-specific-columns – Petros Splinakis Mar 15 '15 at 20:14
  • @Petros Splinakis Thanks but the problem here is we have to iterate all result to extract the only field value. Select only return a collection of Objects. There is no option to select a single field and get the result list directly like in the JPQL. – Dreamer Mar 15 '15 at 21:49

2 Answers2

7

The JPA Metamodel API can be used for this.

CriteriaBuilder builder = entityManager.getCriteriaBuilder();
CriteriaQuery<Long> query = builder.createQuery(String.class);
Root<Order> root = query.from(Orders.class);
query.select(root.get(Orders_.id));

Here, Orders_ is the metamodel class for the Orders entity.

manish
  • 19,695
  • 5
  • 67
  • 91
  • Thanks. So in such situation it is better to create metaModel class for the entity class? Also is it ok if I only place only id field in the metaModel class? – Dreamer Mar 16 '15 at 18:08
  • Sure, if it just one class you could take that approach. Alternatively, you could look at using metamodel generators that would automatically generate the metamodel classes for you. – manish Mar 16 '15 at 18:19
  • The generator should generate classes in the binary code, so I bet it would generate the actual code. Then how can we avoid the errors by IDE(Eclipse may complaint about the class does not exist) – Dreamer Mar 16 '15 at 19:47
  • 1
    Not necessarily. Some generators generate the source code for the metamodel classes just before the compilation stage. Sometimes you have control over where these classes are generated. You can add the generation location to your Eclipse project classpath. If this doesn't work for you, you can always generate the metamodel classes manually. In any case, your original question has been answered as Eclipse errors were not part of your original question. You should try the proposed solution and if you run into errors specific to the IDE you are using, you should raise a separate question. – manish Mar 17 '15 at 05:41
  • Thanks a lot for the instructions ! – Dreamer Mar 17 '15 at 14:09
2

Although it can be done with the optional JPA Metamodel API, it can even be done using the plain Criteria API itself.

It looks that the select item is defined by builder.createQuery(Order.class) already without any flexibility.

If you want to select the id of an order, then you shouldn't use createQuery(Order.class), because that could cause the result to be an order instead of an id of an order. You should use the format createQuery(ResultType.class). So if the id is for example a Java Long, then you should use createQuery(Long.class).

So instead of this:

CriteriaBuilder builder = kem.getCriteriaBuilder();
CriteriaQuery<Orders> query = builder.createQuery(Orders.class);
Root<Order> orders = query.from(Orders.class);
query.select(orders);
....

It should be:

CriteriaBuilder builder = kem.getCriteriaBuilder();
CriteriaQuery<Long> query = builder.createQuery(Long.class);
Root<Order> orders = query.from(Orders.class);
query.select("id"); // or query.select(orders.get("id"))
....

You can even navigate using path navigation:

query.select(orders.get("customer").get("address").get("streetNumber"));
Devabc
  • 4,782
  • 5
  • 27
  • 40