Criteria API: filter by class type

佐手、 提交于 2019-12-30 06:58:26

问题


I'm relativley new to relational databases and I have some problems concerning the creation of queries. First I want to explain the situation shortly. I have several entity classes. All of them extend AbstractEntity or EntityProperty. So entities can have properties and properties have owning entities, so there is a bidirectional relation.
Now let's say ConcreteEntity extends AbstractEntity and I want to create queries like this: Get all entities of type ConcreteEntity which has at least on property with a name contained in the given list propertyNames. Until now I have the following working 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 want only those entities of type ConcreteEntity. How could I achieve this? In JPQL I wrote "SELECT entity FROM EntityProperty property JOIN property.owningEntities entity" and here I also have no idea how to write it in the way that only a specific type is returned...

Thanks for answers in advance!

EDIT: moved the second question to criteria query: indistinct result lists and removed distinct in the code (that didn't work)


回答1:


I know this is an old question but just in case someone stumbles upon the same problem, here is how it can be solved. You can easily filter by entity type like this:

Predicate p = cb.equal(entity.type(), cb.literal(ConcreteEntity.class));

where entity can be a 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);



回答2:


The only way I found until now was to create an enumeration with a value for each class The resulting criteria query is

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, every entity now has the attribute entityType. I also have to create the collection suitableSubTypes every time. Another problem is that the returned type is List<AbstractEntity>. What I wanted was a method signature like

public static <T extends AbstractEntity> List<T>
                getEntities(Class<T> entityClass, String... propertyNames)

but for now I have

public static List<AbstractEntity>
                getEntities(Collection<AbstractEntityType> suitableSubTypes,
                String... propertyNames)

So I still hope there exists a better solution...



来源:https://stackoverflow.com/questions/26226031/criteria-api-filter-by-class-type

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!