从JPA Native Query获取列名

时间:2017-06-19 09:18:45

标签: java sql hibernate jpa

我的Web应用程序中有一个管理控制台,允许管理员在我们的数据库上执行自定义SQL SELECT查询。

下面,应用程序正在使用Hibernate,但这些查询不是HQL,它们是纯SQL,所以我使用的是这样的Native Query:

protected EntityManager em;

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

这可以正常工作,但它只返回数据行,没有额外的信息。我想要的是获取列名,所以当我将结果打印回给用户时,我还可以打印一个标题来显示各列的内容。

有没有办法做到这一点?

7 个答案:

答案 0 :(得分:3)

此代码对我有用

DTO类别:

 PASS  src/stackoverflow/58085900/index.spec.tsx
  SomeComponent
    #handleSubmit
      ✓ check submit (17ms)
      ✓ should alert when first name is invalid (5ms)
      ✓ should alert when last name is invalid (3ms)
    #getFullName
      ✓ should fetch data correctly (3ms)
      ✓ should alert when fetch data error (2ms)

-----------|----------|----------|----------|----------|-------------------|
File       |  % Stmts | % Branch |  % Funcs |  % Lines | Uncovered Line #s |
-----------|----------|----------|----------|----------|-------------------|
All files  |    89.19 |      100 |       90 |    88.24 |                   |
 index.tsx |    89.19 |      100 |       90 |    88.24 |       58,59,60,62 |
-----------|----------|----------|----------|----------|-------------------|
Test Suites: 1 passed, 1 total
Tests:       5 passed, 5 total
Snapshots:   3 passed, 3 total
Time:        4.925s, estimated 6s

服务类别在下面

 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;
}

}

答案 1 :(得分:2)

Ryiad的答案DTO带来了一些混乱,您应该将其保留下来。 您应该已经解释过它仅适用于休眠状态。

如果像我一样需要保持列的顺序,则可以指定自己的转换器。我从休眠中复制了代码,并将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();

答案 2 :(得分:0)

如果JPA提供程序不支持查询元数据的检索,则另一种解决方案可能是使用诸如JSQLParserZQLGeneral SQL Parser(商业)之类的SQL解析器来提取SELECT语句中的字段。

答案 3 :(得分:0)

很长一段时间没有答案,并且根据我自己的进一步研究,看来这无法完成。

答案 4 :(得分:0)

使用JPA时,我也遇到类似的问题。 JPA中没有直接方法来访问结果集元数据。解决方案可以是从查询本身中提取列名称,也可以使用JDBC获取元数据。

答案 5 :(得分:0)

将查询转换为休眠查询,然后使用休眠方法

          //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());

答案 6 :(得分:0)

2019

使用休眠模式5.2.11。最终实际上很容易。

Query q = em.createNativeQuery("SELECT columnA, columnB FROM table");
List<Tuple> result = q.getResultList();
for (Tuple row: result){
    Object columnA;
    Object columnB;
    try {
        columnA = row.get("columnA");
        columnB= row.get("columnB");
    } catch (IllegalArgumentException e) {
        System.out.println("A column was not found");
    }
}