2011-12-19 4 views
1

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

неудачу вызов: 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); 
} 

ответ

2

Для доступа к полям, которые являются членами IdClass вы должны использовать metamodel.

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

Если вы не хотите, чтобы сгенерировать статический метамодель, то есть еще следующие довольно плохой способ доступа к атрибутам идентификатора:

//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); 
Смежные вопросы