调用javax.persistence.criteria.Path.get(String name)
失败,下面详细介绍了简单的类层次结构。如果@IdClass
和第二个id字段(即id2
)被移除,则呼叫成功。有人知道为什么会这样吗?这是否意味着不能查询单个id字段,而该id字段是复合键的一部分?
呼叫失败是:Path<Object> path = entity.get(name);
private static final EntityManager em;
private final CriteriaBuilder cb = em.getCriteriaBuilder();
private final CriteriaQuery<Y> query = cb.createQuery(Y.class);
private final Root<Y> entity = query.from(Y.class);
static {
Map<String, Object> properties = new HashMap<String, Object>();
// initialise properties appropriately
EntityManagerFactory emf =
Persistence.createEntityManagerFactory("test", properties);
em = emf.createEntityManager();
}
interface PK {
Object getPK();
}
public static class YPK implements Serializable {
int id;
int id2;
YPK(int id, int id2) { }
// Override hashCode() and equals() appropriately
}
@IdClass(YPK.class)
@Entity
public static class Y implements Serializable, PK {
@Id
int id;
@Id
int id2;
protected Y() { }
public Y(int id) {
this.id = id;
}
@Override
public Object getPK() {
return id;
}
}
@Test
public void simpleTest() {
List<Y> yy = new ArrayList<Y>();
Y yX1 = new Y(5);
yy.add(yX1);
Y yX2 = new Y(6);
yy.add(yX2);
saveItems(yy);
String name = "id";
Path<Object> path = entity.get(name);
Predicate restriction = cb.conjunction();
restriction = cb.and(restriction, cb.and(new Predicate[]{cb.equal(path, 5)}));
TypedQuery<Y> tq = em.createQuery(this.query);
Y result = null;
try {
result = tq.getSingleResult();
} catch (NoResultException e) {
}
assertNotNull(result);
}
要访问作为IdClass成员的字段,您需要使用元模型。
我建议使用静态元模型,因为它更干净,类型更安全。您可以使用工具生成它,也可以自己编写它。对于类Y,它将是这样的:
import javax.persistence.metamodel.MapAttribute;
import javax.persistence.metamodel.SingularAttribute;
import javax.persistence.metamodel.StaticMetamodel;
@StaticMetamodel(Y.class)
public abstract class Y_ {
public static volatile SingularAttribute<Y, Integer> id;
public static volatile SingularAttribute<Y, Integer> id2;
// + similar definitions for other fields:
// <TYPE_OF_ENTITY, TYPE_OF_ATTRIBUTE> NAME_OF_FIELD_IN_ENTITY
}
那么你可以在条件查询中使用IdClass字段:
Path<Integer> pathToId = entity.get(Entity2_.id);
Path<Integer> pathToId2 = entity.get(Entity2_.id2);
如果您不想生成静态元模型,那么仍然有以下一种相当糟糕的方式来访问id的属性:
//find set of all attribute that form id
Metamodel mm = em.getMetamodel();
EntityType et = mm.entity(Y.class);
Set<SingularAttribute> idAttributes = et.getIdClassAttributes();
SingularAttribute idAttribute = null;
//and pick out right one from [id, id2]
for (SingularAttribute candidate : idAttributes) {
if (candidate.getName().equals("id")) {
idAttribute = candidate;
break;
}
}
Path<Integer> path = entity.get(idAttribute);