java - JDBCTemplate 使用 BeanPropertyRowMapper 设置嵌套 POJO

标签 java spring postgresql jdbctemplate

给定以下示例 POJO:(假设所有属性的 Getter 和 Setter)

class User {
    String user_name;
    String display_name;
}

class Message {
    String title;
    String question;
    User user;
}

人们可以轻松地查询数据库(在我的例子中是 postgres)并使用 BeanPropertyRowMapper 填充消息类列表,其中 db 字段与 POJO 中的属性匹配:(假设 DB 表具有与 POJO 属性对应的字段)。

NamedParameterDatbase.query("SELECT * FROM message", new BeanPropertyRowMapper(Message.class));

我想知道 - 有没有一种方便的方法来构造单个查询和/或创建一个行映射器,以便在消息中填充内部“用户”POJO 的属性。

也就是说,查询中每个结果行的一些语法魔术:

SELECT * FROM message, user WHERE user_id = message_id

生成一个带有相关用户填充的消息列表


用例:

最终,这些类作为序列化对象从 Spring Controller 传回,这些类是嵌套的,因此生成的 JSON/XML 具有良好的结构。

目前,这种情况通过执行两个查询并在循环中手动设置每条消息的用户属性来解决。可用,但我想应该可以采用更优雅的方式。


更新:使用的解决方案 -

感谢@Will Keeling 使用自定义行映射器获得答案的灵感 - 我的解决方案添加了 bean 属性映射以自动化字段分配。

需要注意的是构造查询,以便为相关的表名添加前缀(但是没有标准约定来执行此操作,因此查询是以编程方式构建的):

SELECT title AS "message.title", question AS "message.question", user_name AS "user.user_name", display_name AS "user.display_name" FROM message, user WHERE user_id = message_id

然后自定义行映射器创建几个 bean 映射并根据列的前缀设置它们的属性:(使用元数据获取列名)。

public Object mapRow(ResultSet rs, int i) throws SQLException {

    HashMap<String, BeanMap> beans_by_name = new HashMap();

    beans_by_name.put("message", BeanMap.create(new Message()));
    beans_by_name.put("user", BeanMap.create(new User()));

    ResultSetMetaData resultSetMetaData = rs.getMetaData();

    for (int colnum = 1; colnum <= resultSetMetaData.getColumnCount(); colnum++) {

        String table = resultSetMetaData.getColumnName(colnum).split("\\.")[0];
        String field = resultSetMetaData.getColumnName(colnum).split("\\.")[1];

        BeanMap beanMap = beans_by_name.get(table);

        if (rs.getObject(colnum) != null) {
            beanMap.put(field, rs.getObject(colnum));
        }
    }

    Message m = (Task)beans_by_name.get("message").getBean();
    m.setUser((User)beans_by_name.get("user").getBean());

    return m;
}

同样,这对于二类连接来说似乎有点过头了,但 IRL 用例涉及具有数十个字段的多个表。

最佳答案

也许您可以传入一个自定义 RowMapper,它可以将聚合连接查询(在消息和用户之间)的每一行映射到一个 Message 和嵌套的 User 。像这样的:

List<Message> messages = jdbcTemplate.query("SELECT * FROM message m, user u WHERE u.message_id = m.message_id", new RowMapper<Message>() {
    @Override
    public Message mapRow(ResultSet rs, int rowNum) throws SQLException {
        Message message = new Message();
        message.setTitle(rs.getString(1));
        message.setQuestion(rs.getString(2));

        User user = new User();
        user.setUserName(rs.getString(3));
        user.setDisplayName(rs.getString(4));

        message.setUser(user);

        return message;
    }
});

关于java - JDBCTemplate 使用 BeanPropertyRowMapper 设置嵌套 POJO,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16718163/

相关文章:

POSTgreSQL 9.5 : invalid input syntax for integer when trying to copy from CSV

json - 如何将 JSON 提取到表中

java - 如何使用 sed 或 awk 编辑很长的 Java 类

java - 无法启动我的小程序!

java - 单击通知后 Activity 重新启动 - android

Java 验证输入值

spring - 在带有 Hibernate 的 Spring Security 中使用 jdbcAuthentication

java - 如何将服务器证书添加到本地受信任的 Java keystore ?

spring - 如何为 Spring Boot 配置服务器设置超时值

PHP 使用 Propel 从 MySql 迁移到 Postgres