When migrating from Hibernate Criteria api to CriteriaQuery I ran into a generic DAO for a abstract class that has a where on a common field but does a select on their id, even if the ids are totally different per class.
The old projection looks like this
criteria.setProjection(Projections.id());
Is there any way to do this in a similar way with CriteriaQuery?
Edit: Full criteria code
DetachedCriteria detachedCriteria = DetachedCriteria.forClass(MyEntity.class);
detachedCriteria.add(Restrictions.in("accountID", accounts));
detachedCriteria.setProjection(Projections.id());
EntityManager em = ...;
Criteria criteria = detachedCriteria.getExecutableCriteria((Session) em.getDelegate());
List<Integer> list = criteria.list();
I just managed to find it on my own.
criteriaQuery.select(
root.get(entityRoot.getModel().getDeclaredId(int.class))
);
Combining answers:
https://stackoverflow.com/a/16911313
https://stackoverflow.com/a/47793003
I created this method:
public String getIdAttribute(EntityManager em, String fullClassName) {
Class<? extends Object> clazz = null;
try {
clazz = Class.forName(fullClassName);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
Metamodel m = em.getMetamodel();
IdentifiableType<T> of = (IdentifiableType<T>) m.managedType(clazz);
return of.getId(of.getIdType().getJavaType()).getName();
}
then I have the entity manager injected
@PersistenceContext
private EntityManager em;
I get the root entity primary key like that:
String rootFullClassName = root.getModel().getJavaType().getName();
String primaryKeyName = getIdAttribute(em, rootFullClassName);
and I get the primary keys referenced on attributes like that:
return (Specification<T>) (root, query, builder) -> {
Set<Attribute<? super T, ?>> attributes = root.getModel().getAttributes();
for (Attribute a: attributes) {
if(a.isAssociation()) {
Path rootJoinGetName = root.join(a.getName());
String referencedClassName = rootJoinGetName.getJavaType().getName();
String referencedPrimaryKey = getIdAttribute(em, referencedClassName);
//then I can use it to see if it is equal to a value (e.g
//filtering actors by movies with id = 1 - in
//this case referencedPrimaryKey is "id")
Predicate p = rootJoinGetName.get(referencedPrimaryKey).in(1);
}
}
}
In this way I don't need to know the type of the primary key/referenced key in advance as it can be derived through the Entity Manager Meta Model. The above code can be used with CriteriaQuery as well as Specifications.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With