Hibernate 4.0: javax.persistence.criteria.Path.get在指定复合键字段时失



调用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);

最新更新