使用CriteriaQuery

时间:2018-05-25 08:50:20

标签: java hibernate jpa criteriaquery

当从Hibernate Criteria api迁移到CriteriaQuery时,我遇到了一个抽象类的泛型DAO,该抽象类在公共字段上有一个where但在id上有select,即使每个类的id完全不同。

旧投影看起来像这样

criteria.setProjection(Projections.id());

有没有办法以类似的方式使用CriteriaQuery做到这一点?

编辑:完整标准代码

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();

2 个答案:

答案 0 :(得分:3)

我只是设法自己找到它。

criteriaQuery.select(
    root.get(entityRoot.getModel().getDeclaredId(int.class))
);

答案 1 :(得分:1)

合并答案:

https://stackoverflow.com/a/16911313

https://stackoverflow.com/a/47793003

我创建了此方法:

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();
}

然后我注入了实体经理

@PersistenceContext
private EntityManager em;

我得到了这样的根实体主键:

String rootFullClassName = root.getModel().getJavaType().getName();
String primaryKeyName = getIdAttribute(em, rootFullClassName);

我得到了像这样的属性所引用的主键:

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);
        }
    }
}

通过这种方式,我不需要事先知道主键/引用键的类型,因为它可以通过实体管理器元模型派生。上面的代码可以与CriteriaQuery以及Specification一起使用。