Hibernate 4.0: javax.persistence.criteria.Path.get завершается ошибкой, когда указано поле составного ключа - PullRequest
1 голос
/ 19 декабря 2011

Вызов javax.persistence.criteria.Path.get(String name) завершается неудачно для простой иерархии классов, описанной ниже. Вызов завершается успешно, если @IdClass и второе поле идентификатора (т.е. id2) удалены. Кто-нибудь знает, почему это так. Означает ли это, что невозможно запросить одно поле идентификатора, где это поле идентификатора является частью составного ключа?

сбой вызова: 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);
}

1 Ответ

2 голосов
/ 19 декабря 2011

Для доступа к полям, которые являются членами 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);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...