web-dev-qa-db-ja.com

JPAネイティブクエリからの列名の取得

Webアプリケーションに管理コンソールがあり、管理者がデータベースでカスタムSQL SELECTクエリを実行できます。

その下では、アプリケーションはHibernateを使用していますが、これらのクエリはHQLではなく、純粋なSQLであるため、次のようなネイティブクエリを使用しています。

protected EntityManager em;

public List<Object[]> execute(String query) {
    Query q = em.createNativeQuery(query);
    List<Object[]> result = q.getResultList();
    return result;
}

これは正しく機能しますが、追加の情報なしでデータの行のみを返します。列名も取得したいので、結果をユーザーに印刷するときに、ヘッダーを印刷して、さまざまな列が何であるかを示すこともできます。

これを行う方法はありますか?

10
Master_T

長い間答えがなかった後、そして私自身のさらなる研究に基づいて、これは残念ながら行うことができないようです。

0
Master_T

このコードは私のために働いた

DTOクラス:

 public class ItemResponse<T> {

 private T item;

 public ItemResponse() {
 }

 public ItemResponse(T item) {
   super();
   this.item = item;
 }

 public T getItem() {
    return item;
}

public void setItem(T item) {
    this.item = item;
}

}

サービスクラスは以下にあります

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import org.springframework.stereotype.Service;
import org.hibernate.transform.AliasToEntityMapResultTransformer;

@Service
public class ServiceClass{ 

@PersistenceContext
public EntityManager entityManager;

public ItemResponse exceuteQueryResponse(String queryString) {

        ItemResponse itemResponse=new ItemResponse();           
        Query jpaQuery =  entityManager.createNativeQuery(queryString);
        org.hibernate.Query hibernateQuery =((org.hibernate.jpa.HibernateQuery)jpaQuery).getHibernateQuery();
      hibernateQuery.setResultTransformer(AliasToEntityMapResultTransformer.INSTANCE);
        List<Map<String,Object>> res = hibernateQuery.list();

        itemResponse.setItem(res);
        return itemResponse;

    }

    }
3
Riyad

また、JPAでの作業でも同様の問題に直面しました。 JPAでは、結果セットのメタデータに直接アクセスする方法はありません。解決策は、クエリ自体から列名を抽出するか、JDBCを使用してメタデータを取得することです。

0
utkarsh pandey

クエリをhibernateクエリにキャストし、hibernateメソッドを使用する

          //normal use, javax.persistence.Query interface
    Query dbQuery = entityManager.createNativeQuery(sql);
    //cast to hibernate query
    org.hibernate.Query hibernateQuery =((org.hibernate.jpa.HibernateQuery)dbQuery)
            .getHibernateQuery();
    hibernateQuery.setResultTransformer(AliasToEntityMapResultTransformer.INSTANCE);

    List<Map<String,Object>> res = hibernateQuery.list();

    List<TxTestModel> txTestModels = new ArrayList<>();
    res.forEach(e->{
        TxTestModel txTestModel = new ObjectMapper().convertValue(e, TxTestModel.class);
    //  txTestModels.add(new TxTestModel().setIdd((Integer) e.get("idd")).setMmm((String) e.get("mmm")).setDdd((Date) e.get("ddd")));
        txTestModels.add(txTestModel);
    });
    System.out.println(txTestModels.size());
0
Luke Cheung

Ryiadの回答DTOは混乱を招くので、避けておくべきでした。 htatはhibernateでのみ機能することを説明したはずです。

私のように列の順序を維持する必要がある場合は、独自のトランスフォーマーを指定できます。コードをhibernateからコピーして、HashMapをLinkedHashMapに変更しました。

import Java.util.LinkedHashMap;
import Java.util.Map;

import org.hibernate.transform.AliasedTupleSubsetResultTransformer;
import org.hibernate.transform.ResultTransformer;

/**
 * {@link ResultTransformer} implementation which builds a map for each "row", made up of each aliased value where the
 * alias is the map key. Inspired by {@link org.hibernate.transform.AliasToEntityMapResultTransformer}, but kepping the
 * ordering of elements.
 * <p/>
 * Since this transformer is stateless, all instances would be considered equal. So for optimization purposes we limit
 * it to a single, singleton {@link #INSTANCE instance}.
 */
public class AliasToEntityMapResultTransformer extends AliasedTupleSubsetResultTransformer {

    public static final AliasToEntityMapResultTransformer INSTANCE = new AliasToEntityMapResultTransformer();

    /**
     * Disallow instantiation of AliasToEntityMapResultTransformer.
     */
    private AliasToEntityMapResultTransformer() {
    }

    @Override
    public Object transformTuple(Object[] Tuple, String[] aliases) {
        Map result = new LinkedHashMap<>(Tuple.length);
        for (int i = 0; i < Tuple.length; i++) {
            String alias = aliases[i];
            if (alias != null) {
                result.put(alias, Tuple[i]);
            }
        }
        return result;
    }

    @Override
    public boolean isTransformedValueATupleElement(String[] aliases, int tupleLength) {
        return false;
    }

    /**
     * Serialization hook for ensuring singleton uniqueing.
     *
     * @return The singleton instance : {@link #INSTANCE}
     */
    private Object readResolve() {
        return INSTANCE;
    }
}

このトランスフォーマーを使用すると、RyiadのソリューションをHibernateで使用できます。

    Query jpaQuery =  entityManager.createNativeQuery(queryString);
    org.hibernate.Query hibernateQuery =((org.hibernate.jpa.HibernateQuery)jpaQuery).getHibernateQuery();
  hibernateQuery.setResultTransformer(AliasToEntityMapResultTransformer.INSTANCE);
    List<Map<String,Object>> res = hibernateQuery.list();
0
Nicolas

JPAプロバイダーがクエリメタデータの取得をサポートしていない場合、別の解決策は JSQLParser[〜#〜] zql [〜#〜] のようなSQLパーサーの使用です。 =または 一般的なSQLパーサー (商用)、SELECTステートメントからフィールドを抽出します。

0
ltlBeBoy