我的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;
}
这可以正常工作,但它只返回数据行,没有额外的信息。我想要的是获取列名,所以当我将结果打印回给用户时,我还可以打印一个标题来显示各列的内容。
有没有办法做到这一点?
答案 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提供程序不支持查询元数据的检索,则另一种解决方案可能是使用诸如JSQLParser,ZQL或General 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");
}
}