从JPA Native Query获取列名

Mas*_*r_T 10 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;
}
Run Code Online (Sandbox Code Playgroud)

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

有没有办法做到这一点?

gee*_*kfa 19

Query query = entityManager.createNamedQuery(namedQuery);
NativeQueryImpl nativeQuery = (NativeQueryImpl) query;
nativeQuery.setResultTransformer(AliasToEntityMapResultTransformer.INSTANCE);
List<Map<String,Object>> result = nativeQuery.getResultList();
Run Code Online (Sandbox Code Playgroud)

现在你有了Map<String,Object>。您可以看到您的列名称

  • 非常感谢你花了一整天的时间我找到了解决方案:)你拯救了我的一天 (3认同)

小智 7

这段代码对我有用

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

}
Run Code Online (Sandbox Code Playgroud)

服务等级如下

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;

    }

    }
Run Code Online (Sandbox Code Playgroud)


Jes*_*sta 5

2020年

使用 hibernate 5.2.11.Final 实际上很容易。在我的示例中,您可以看到我如何获取每一行的列名。以及我如何按列名获取值。

Query q = em.createNativeQuery("SELECT columnA, columnB FROM table");
List<Tuple> result = q.getResultList();

for (Tuple row: result){

    // Get Column Names
    List<TupleElement<Object>> elements = row.getElements();
    for (TupleElement<Object> element : elements ) {
        System.out.println(element.getAlias());
    }

    // Get Objects by Column Name
    Object columnA;
    Object columnB;
    try {
        columnA = row.get("columnA");
        columnB= row.get("columnB");
    } catch (IllegalArgumentException e) {
        System.out.println("A column was not found");
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 似乎这不适用于 5.4.2.Final 等更高版本,因为返回的是对象列表。 (3认同)

Nic*_*las 5

Ryiad 的回答 DTO 增加了一些混乱,你应该把它远离。您应该已经解释过它仅适用于休眠。

如果像我一样您需要保持列的顺序,您可以指定您自己的变压器。我从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;
    }
}
Run Code Online (Sandbox Code Playgroud)

有了这个变压器,您可以将 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();
Run Code Online (Sandbox Code Playgroud)


Mas*_*r_T 1

很长一段时间没有任何答案,并且根据我自己的进一步研究,似乎这是不可能的,不幸的是。

  • 这些库是否适合您:“javax.persistence.Query”、“org.eclipse.persistence.config.QueryHints”、“org.eclipse.persistence.config.ResultType”?您可以将查询设置为`QueryHints.RESULT_TYPE, ResultType.Map`:`myEntityMananger.createNativeQuery("select * from mytable").setHint(QueryHints.RESULT_TYPE, ResultType.Map);`。然后通过映射键访问列名称 (4认同)
  • 美好的一天@vc73:我不确定我还能展示什么。您是否已经用具体的查询条件填写了我上面给定的代码模板?那么,您查看过您的结果列表吗?我将向您展示再次处理的步骤: `//您的结果列表` `List myResult = res;` `//您通过实体管理器的查询` `res = myEntityMananger.createNativeQuery("select * from mytable") .setHint (QueryHints.RESULT_TYPE, ResultType.Map) .getResultList();` 查看您的 `res` 变量,您可以转换列表中的每个条目: `int i = 1;` `List&lt;Map&gt; data = (List) res.get(i);` (2认同)
  • @WileE.Genius:很高兴在这里为您提供帮助。这个平台不是为了帮助人们,而是为了遵守法律和秩序体系。由于我不确定 eclipse link 如何或是否适合休眠,这里的人们肯定会抱怨“eclipse link”不是原始问题的标签,因此会告诉我“这不能回答问题”加上 put贬值就可以了。 (2认同)
  • 嗨@woodz!非常感谢您的回答,因为它节省了我很多时间。我必须稍微调整一下,但效果完美。这是我的起点: `List&lt;DatabaseRecord&gt; res = this.em.createNativeQuery(selectStmt).setHint(QueryHints.RESULT_TYPE, ResultType.Map).getResultList();` DatabaseRecord 似乎是要使用的类,因为它没有不驻留在 Eclipselink 的内部包中。 (2认同)