2011-12-19 7 views
1

javax.persistence.criteria.Path.get(String name)を呼び出すことは、以下で説明する単純なクラス階層では失敗します。 @IdClassと2番目のIDフィールド(つまりid2)が削除された場合、呼び出しは成功します。誰でもこれがなぜそうであるか知っている。これは、そのidフィールドがコンポジットキーの一部を形成する単一の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

は、あなたがmetamodelを使用する必要がIdClassのメンバーであるフィールドにアクセスするには。

静的メタモデルを使用することをお勧めします。これは、よりクリーンで種類が安全なためです。あなたはツールを使ってそれを生成したり、あなた自身で書くことができます。あなたは、静的なメタモデルを生成したくない場合は、まだかなりあっ以下れる

Path<Integer> pathToId = entity.get(Entity2_.id); 
Path<Integer> pathToId2 = entity.get(Entity2_.id2); 

:あなたは基準クエリでIdClassフィールドを使用することができます次に

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 
} 

:クラスの場合、それは何かのようになりますY 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);