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;
}
これは正しく機能しますが、追加の情報なしでデータの行のみを返します。列名も取得したいので、結果をユーザーに印刷するときに、ヘッダーを印刷して、さまざまな列が何であるかを示すこともできます。
これを行う方法はありますか?
長い間答えがなかった後、そして私自身のさらなる研究に基づいて、これは残念ながら行うことができないようです。
このコードは私のために働いた
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;
}
}
また、JPAでの作業でも同様の問題に直面しました。 JPAでは、結果セットのメタデータに直接アクセスする方法はありません。解決策は、クエリ自体から列名を抽出するか、JDBCを使用してメタデータを取得することです。
クエリを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());
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();
JPAプロバイダーがクエリメタデータの取得をサポートしていない場合、別の解決策は JSQLParser 、 [〜#〜] zql [〜#〜] のようなSQLパーサーの使用です。 =または 一般的なSQLパーサー (商用)、SELECT
ステートメントからフィールドを抽出します。