API Criteria: Filter by Class Type
I am new to relational databases and I have some problems with building queries. First, I want to briefly explain the situation. I have multiple entity classes. They all expand AbstractEntity
or EntityProperty
. Thus, objects can have properties and properties that have their own objects, so there is a bi-directional relationship.
Now let's say ConcreteEntity
extends AbstractEntity
and I want to create queries like this: Get all entities of a type ConcreteEntity
that have at least a property named in the given list propertyNames
. So far, I have the following performance criteria query:
CriteriaQuery<AbstractEntity> cq = cb.createQuery(AbstractEntity.class);
Root<EntityProperty> property = cq.from(EntityProperty.class);
Join<EntityProperty, AbstractEntity> entity = property.join(EntityProperty_.owningEntities);
cq.where(property.get(EntityProperty_.name).in((Object[]) propertyNames));
cq.select(entity);
But now I only want those type objects ConcreteEntity
. How could I achieve this? In JPQL I wrote "SELECT entity FROM EntityProperty property JOIN property.owningEntities entity" and here I also don't know how to write it in such a way that only the specific type is returned ...
Thanks for the answers in advance!
EDIT: Moved second question to criteria query: fuzzy result lists and removed in code the code (which didn't work)
source to share
I know this is an old question, but just in case someone comes across the same problem, here's how to solve it. You can easily filter by object type like this:
Predicate p = cb.equal(entity.type(), cb.literal(ConcreteEntity.class));
where entity can be Path (Root and Join included), cb is a CriteriaBuilder object. So in your case it would be something like this:
CriteriaQuery<AbstractEntity> cq = cb.createQuery(AbstractEntity.class);
Root<EntityProperty> property = cq.from(EntityProperty.class);
Join<EntityProperty, AbstractEntity> entity = property.join(EntityProperty_.owningEntities);
cq.where(cb.and(
property.get(EntityProperty_.name).in((Object[]) propertyNames),
cb.equal(entity.type(), cb.literal.ConcreteEntity.class)
));
cq.select(entity);
source to share
The only way I've found so far is to create an enum with a value for each class. As a result of a criteria query
CriteriaQuery<AbstractEntity> cq = cb.createQuery(AbstractEntity.class);
Root<EntityProperty> property = cq.from(EntityProperty.class);
SetJoin<EntityProperty, AbstractEntity> entity =
property.join(EntityProperty_.owningEntities);
cq.where(property.get(EntityProperty_.name).in((Object[]) propertyNames),
entity.get(AbstractEntity_.entityType).in(suitableSubTypes));
cq.select(entity);
List<AbstractEntity> resultList = em.createQuery(cq).getResultList();
As you can see, each entity now has an entityType attribute. I also have to create a collection of suitable SubTypes every time. Another problem is that the return type List<AbstractEntity>
. What I wanted was a method signature like
public static <T extends AbstractEntity> List<T>
getEntities(Class<T> entityClass, String... propertyNames)
but at the moment i
public static List<AbstractEntity>
getEntities(Collection<AbstractEntityType> suitableSubTypes,
String... propertyNames)
So, I still hope there is a better solution ...
source to share