Java Hibernate:在名为query的存储过程中映射自定义列名
我当前有以下围绕存储过程的命名查询:-Java Hibernate:在名为query的存储过程中映射自定义列名,java,hibernate,stored-procedures,named-query,Java,Hibernate,Stored Procedures,Named Query,我当前有以下围绕存储过程的命名查询:- <hibernate-mapping> <sql-query name="mySp"> <return-scalar column="name_first" type="string" /> <return-scalar column="name_last" type="string" /> { call some_sp :param } &l
<hibernate-mapping>
<sql-query name="mySp">
<return-scalar column="name_first" type="string" />
<return-scalar column="name_last" type="string" />
{ call some_sp :param }
</sql-query>
</hibernate-mapping>
调用命名查询并将结果映射到bean的Hibernate代码:-
MyBean myBean = (MyBean) sessionFactory.getCurrentSession()
.getNamedQuery("mySp")
.setParameter("param", param)
.setResultTransformer(Transformers.aliasToBean(MyBean.class))
.uniqueResult();
所有这些都很好,但我不想依赖存储过程中的列名,而是想在MyBean
中使用我自己的列名,例如:-
public class MyBean {
private String firstName; // instead of name_first
private String lastName; // instead of name_last
...
}
如何将列名映射到上面命名查询中存储过程的列
谢谢
更新-我在下面添加了我的最终解决方案。您需要实现自己的ResultTransformer。这非常简单,您可以查看捆绑实现的来源以获得灵感
只需手动构建bean:
Object[] columns = (Object[]) sessionFactory.getCurrentSession()
.getNamedQuery("mySp")
.setParameter("param", param)
.uniqueResult();
MyBean myBean = new MyBean((String) columns[0], (String) columns[1]);
这还有一个额外的优点:它允许您使MyBean不可变。基于@partenon关于使用自定义
结果转换器的回答,这里是最终的解决方案:-
MyBean myBean = (MyBean) sessionFactory.getCurrentSession()
.getNamedQuery("mySp")
.setParameter("param", param)
.setResultTransformer(new BasicTransformerAdapter() {
private static final long serialVersionUID = 1L;
@Override
public Object transformTuple(Object[] tuple, String[] aliases) {
String firstName = (String) tuple[0];
String lastName = (String) tuple[1];
return new MyBean(firstName, lastName);
}
})
.uniqueResult();
对于非托管和非实体类型,您仍然希望使用支持@Column注释的类型转换器。以下是方法:
以下是实体类型:
@Data /* lombok */
public class MyType {
@Column(name = "field1")
private String normalFieldName;
@Column(name = "field2")
private String normalFieldNameAnother;
}
以下是存储库功能代码:
// alias mapper that do convert from column manes to field names based on @Column annotation
Function<String[], String[]> aliasesTransformer = new Function<String[], String[]>() {
private final Map<String, Field> fieldAliasToField = Stream.of(FieldUtils.getFieldsWithAnnotation(MyType.class, Column.class))
.collect(Collectors.toMap(f -> f.getAnnotation(Column.class).name(), Functions.identity()));
@Override
public String[] apply(String[] o) {
return Stream.of(o).map(el -> {
if (fieldAliasToField.containsKey(el)) {
return fieldAliasToField.get(el).getName();
} else {
return el;
}
}).toArray(String[]::new);
}
};
String sql = "select\n"
+ " h.field1, "
+ " s.field2, "
+ "from "
+ " table1 s, "
+ " table2 h "
+ "where "
+ " s.common_key = h.common_key";
EntityManager em = emf.createEntityManager();
//noinspection unchecked
List<MyType> res = (List<MyType>)em.createNativeQuery(sql)
.unwrap(org.hibernate.query.Query.class)
.setResultTransformer(new AliasToBeanResultTransformer(MyType.class) {
@Override
public Object transformTuple(Object[] tuple, String[] aliases) {
return super.transformTuple(tuple, aliasesTransformer.apply(aliases));
}
}).list();
//基于@column annotation将列名称转换为字段名称的别名映射器
函数别名Transformer=新函数(){
私有最终映射fieldAliasToField=Stream.of(FieldUtils.getFieldsWithAnnotation(MyType.class,Column.class))
.collect(Collectors.toMap(f->f.getAnnotation(Column.class).name(),Functions.identity());
@凌驾
公共字符串[]应用(字符串[]o){
返回流.of(o).map(el->{
if(fieldAliasToField.containsKey(el)){
返回fieldAliasToField.get(el.getName();
}否则{
返回el;
}
}).toArray(字符串[]::新建);
}
};
String sql=“选择\n”
+“h.field1,”
+“s.field2,”
+“来自”
+表1
+“表2 h”
+“哪里”
+“s.common_key=h.common_key”;
EntityManager em=emf.createEntityManager();
//未检查
List res=(List)em.createNativeQuery(sql)
.unwrap(org.hibernate.query.query.class)
.setResultTransformer(新别名为BeanResultTransformer(MyType.class)){
@凌驾
公共对象转换元组(对象[]元组,字符串[]别名){
返回super.transformTuple(tuple,aliasesTransformer.apply(别名));
}
}).list();
谢谢,我在Answers
section.limc中添加了我的最终解决方案,您是否在org.hibernate.loader.loader.processResultSet(loader.java:950)的org.hibernate.loader.loader.doQuery(loader.java:921)中的线程“main”java.lang.NullPointerException中有异常在org.hibernate.loader.loader.doQueryAndInitializeNonLazyCollections(loader.java:355)在org.hibernate.loader.loader.doList(loader.java:2554)在org.hibernate.loader.loader.listIgnoreQueryCache(loader.java:2370)上?
// alias mapper that do convert from column manes to field names based on @Column annotation
Function<String[], String[]> aliasesTransformer = new Function<String[], String[]>() {
private final Map<String, Field> fieldAliasToField = Stream.of(FieldUtils.getFieldsWithAnnotation(MyType.class, Column.class))
.collect(Collectors.toMap(f -> f.getAnnotation(Column.class).name(), Functions.identity()));
@Override
public String[] apply(String[] o) {
return Stream.of(o).map(el -> {
if (fieldAliasToField.containsKey(el)) {
return fieldAliasToField.get(el).getName();
} else {
return el;
}
}).toArray(String[]::new);
}
};
String sql = "select\n"
+ " h.field1, "
+ " s.field2, "
+ "from "
+ " table1 s, "
+ " table2 h "
+ "where "
+ " s.common_key = h.common_key";
EntityManager em = emf.createEntityManager();
//noinspection unchecked
List<MyType> res = (List<MyType>)em.createNativeQuery(sql)
.unwrap(org.hibernate.query.Query.class)
.setResultTransformer(new AliasToBeanResultTransformer(MyType.class) {
@Override
public Object transformTuple(Object[] tuple, String[] aliases) {
return super.transformTuple(tuple, aliasesTransformer.apply(aliases));
}
}).list();