2012-09-27 24 views
42

特定の列(例:SELECT a FROM b)のみを選択したいと考えています。私は、ジェネリックDAOを持っているし、私が思い付いたことは次のとおりです。JPA&Criteria API - 特定の列のみを選択する

public List<T> getAll(boolean idAndVersionOnly) { 
    CriteriaBuilder builder = manager.getCriteriaBuilder(); 
    CriteriaQuery<T> criteria = builder.createQuery(entityClazz); 
    Root<T> root = criteria.from(entityClazz); 
    if (idAndVersionOnly) { 
     criteria.select(root.get("ID").get("VERSION")); // HERE IS ERROR 
    } else { 
     criteria.select(root); 
    } 
    return manager.createQuery(criteria).getResultList(); 
} 

し、エラーがある: The method select(Selection<? extends T>) in the type CriteriaQuery<T> is not applicable for the arguments (Path<Object>)。それをどうやって変えるべきですか?私はIDフィールドとVERSIONフィールドしか持たないタイプTオブジェクトを取得したい、それ以外はnullです。

タイプT extend AbstractEntityこれらの2つのフィールドがあります。

entityClazzT.classです。

答えて

58

特定の列のみを取得するJPAの方法の1つは、Tupleオブジェクトを要求することです。あなたのケースでは

あなたはこのような何かを書く必要があります:あなたはあなたのケースでTのような結果を表すクラスを、持っている場合

CriteriaQuery<Tuple> cq = builder.createTupleQuery(); 
// write the Root, Path elements as usual 
Root<EntityClazz> root = cq.from(EntityClazz.class); 
cq.multiselect(root.get(EntityClazz_.ID), root.get(EntityClazz_.VERSION)); //using metamodel 
List<Tuple> tupleResult = em.createQuery(cq).getResultList(); 
for (Tuple t : tupleResult) { 
    Long id = (Long) t.get(0); 
    Long version = (Long) t.get(1); 
} 

別のアプローチが可能です。 Tは、Entityクラスである必要はありません。 Tは、コンストラクタのように持っている場合:

public T(Long id, Long version) 

を、あなたはあなたのCriteriaQueryコンストラクタで直接Tを使用することができます。

CriteriaQuery<T> cq = builder.createQuery(T.class); 
// write the Root, Path elements as usual 
Root<EntityClazz> root = cq.from(EntityClazz.class); 
cq.multiselect(root.get(EntityClazz_.ID), root.get(EntityClazz_.VERSION)); //using metamodel 
List<T> result = em.createQuery(cq).getResultList(); 

は、さらに参考のために、このlinkを参照してください。

2

まず第一に、IDとバージョンのみを持つオブジェクトと他のすべての小道具をnullにする必要があるのは本当にわかりません。しかし、ここではJPA Emを使用しないで、通常のHibernateを使用するコードをいくつか紹介します.JA内で等価を見つけることができます。または、単に代理人からHibernate Session objを取得することが前提です Accessing Hibernate Session from EJB using EntityManager

List<T> results = session.createCriteria(entityClazz) 
    .setProjection(Projections.projectionList() 
     .add(Property.forName("ID")) 
     .add(Property.forName("VERSION")) 
    ) 
    .setResultTransformer(Transformers.aliasToBean(entityClazz); 
    .list(); 

aliasToBeanトランスはそれらを見つけることができなくなりますので、これは、nullに自分のIDとバージョンセットを持つオブジェクトと他のすべての小道具のリストを返します。再び、私は私がそれをしたいと思う状況を考えることができないのか不明です。

+0

ありがとうございます。私は自分のウェブサービスでそれを使いたいと思う。クライアントはIDとバージョンだけを含む「何か」のリストを要求します。次に、それをキャッシュと比較し、変更された完全なオブジェクトを要求します。合理的に聞こえる? – BartoszCichecki

+0

ネットワークの帯域幅を節約することはできますか?データに依存していますが、データが頻繁に変更されることが予想される場合は、「空の」コピーを送信するだけで保存するよりも2つの要求を作成するtcp/ipオーバーヘッドのために帯域幅を無駄にする可能性があります。多分それはチェックアウトする価値がありますか? –

+1

はい、わかっています。私は頻繁に変更されないデータに対してのみ使用するつもりです。 – BartoszCichecki