使用 CriteriaQuery 选择通用主键
Selecting generic primary key with CriteriaQuery
当从 Hibernate Criteria api 迁移到 CriteriaQuery I 运行 到抽象 class 的通用 DAO 时,它在公共字段上有 where 但执行 select 在他们的 id 上,即使每个 class.
的 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();
我自己才找到的。
criteriaQuery.select(
root.get(entityRoot.getModel().getDeclaredId(int.class))
);
合并答案:
我创建了这个方法:
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);
}
}
}
这样我就不需要提前知道主 key/referenced 键的类型,因为它可以通过实体管理器元模型导出。上面的代码可以与 CriteriaQuery 以及 Specifications 一起使用。
当从 Hibernate Criteria api 迁移到 CriteriaQuery I 运行 到抽象 class 的通用 DAO 时,它在公共字段上有 where 但执行 select 在他们的 id 上,即使每个 class.
的 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();
我自己才找到的。
criteriaQuery.select(
root.get(entityRoot.getModel().getDeclaredId(int.class))
);
合并答案:
我创建了这个方法:
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);
}
}
}
这样我就不需要提前知道主 key/referenced 键的类型,因为它可以通过实体管理器元模型导出。上面的代码可以与 CriteriaQuery 以及 Specifications 一起使用。