Hibernate:在存储过程命名查询中映射自定义列名称

发布于 2024-10-15 15:21:49 字数 1275 浏览 3 评论 0原文

我目前有以下围绕存储过程的命名查询:-

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

name_firstname_last 是存储过程返回的确切列名称。我创建了一个包含相同列名的 bean,以便我可以将查询结果映射到该 bean 中。

public class MyBean {
    private String  name_first;
    private String  name_last;  

    ...
}

调用命名查询并将结果映射到 bean 的 Hibernate 代码:-

MyBean myBean = (MyBean) sessionFactory.getCurrentSession()
                        .getNamedQuery("mySp")
                        .setParameter("param", param)
                        .setResultTransformer(Transformers.aliasToBean(MyBean.class))
                        .uniqueResult();

所有这些都工作正常,但我不想依赖存储过程中的列名,而是想在 MyBean< 中使用我自己的列名/code>,例如:-

public class MyBean {
    private String  firstName; // instead of name_first
    private String  lastName;  // instead of name_last  

    ...
}

如何将我的列名称映射到上面命名查询中的存储过程的列?

谢谢。

更新 - 我在下面添加了最终的解决方案。

I currently have the following named query that wraps around a stored procedure:-

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

The columns name_first and name_last are the exact column names returned by the stored procedure. I created a bean that contains the same column names so that I can map the queried result into that bean.

public class MyBean {
    private String  name_first;
    private String  name_last;  

    ...
}

The Hibernate code that calls the named query and map the result into the bean:-

MyBean myBean = (MyBean) sessionFactory.getCurrentSession()
                        .getNamedQuery("mySp")
                        .setParameter("param", param)
                        .setResultTransformer(Transformers.aliasToBean(MyBean.class))
                        .uniqueResult();

All of these work fine, but instead of relying on the column names from the stored procedure, I want to use my own column names in MyBean, for example:-

public class MyBean {
    private String  firstName; // instead of name_first
    private String  lastName;  // instead of name_last  

    ...
}

How do I map my column names against the stored procedure's columns in my named query above?

Thanks.

UPDATE - I added my final solution below.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

哎呦我呸! 2024-10-22 15:21:49

基于@partenon关于使用自定义ResultTransformer的回答,这是最终的解决方案:-

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

Based on @partenon's answer on using a custom ResultTransformer, here's the final solution:-

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();
絕版丫頭 2024-10-22 15:21:49

只需手动构建您的 bean:

Object[] columns = (Object[]) sessionFactory.getCurrentSession()
                        .getNamedQuery("mySp")
                        .setParameter("param", param)
                        .uniqueResult();
MyBean myBean = new MyBean((String) columns[0], (String) columns[1]);

这还有一个额外的优点:它允许您使 MyBean 不可变。

Just build your bean manually :

Object[] columns = (Object[]) sessionFactory.getCurrentSession()
                        .getNamedQuery("mySp")
                        .setParameter("param", param)
                        .uniqueResult();
MyBean myBean = new MyBean((String) columns[0], (String) columns[1]);

This has one additional advantage : it allows you to make your MyBean immutable.

清音悠歌 2024-10-22 15:21:49

对于非托管和非实体类型,您仍然希望使用支持 @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();

For non-managed and non-entity types you still want to use types transformer that do support @Column annotation. Here's how:

Here's entity type:

@Data /* lombok */
public class MyType {
    @Column(name = "field1")
    private String normalFieldName;
    @Column(name = "field2")
    private String normalFieldNameAnother;
}

Here's repository function code:

  // 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();
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文