当前位置: 首页 > 面试题库 >

JDBCTemplate使用BeanPropertyRowMapper设置嵌套的POJO

马才
2023-03-14
问题内容

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

class User {
    String user_name;
    String display_name;
}

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

可以轻松地查询数据库(在我的情况下为postgres),并使用BeanPropertyRowMapper填充Message类的列表,其中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用例涉及具有数十个字段的多个表。


问题答案:

Spring AutoGrowNestedPathsBeanMapper接口中引入了一个新属性。

只要SQL查询使用来格式化列名称。分隔符(如前),那么行映射器将自动定位内部对象。

这样,我创建了一个新的通用行映射器,如下所示:

查询:

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

行映射器:

package nested_row_mapper;

import org.springframework.beans.*;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.support.JdbcUtils;

import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;

public class NestedRowMapper<T> implements RowMapper<T> {

  private Class<T> mappedClass;

  public NestedRowMapper(Class<T> mappedClass) {
    this.mappedClass = mappedClass;
  }

  @Override
  public T mapRow(ResultSet rs, int rowNum) throws SQLException {

    T mappedObject = BeanUtils.instantiate(this.mappedClass);
    BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(mappedObject);

    bw.setAutoGrowNestedPaths(true);

    ResultSetMetaData meta_data = rs.getMetaData();
    int columnCount = meta_data.getColumnCount();

    for (int index = 1; index <= columnCount; index++) {

      try {

        String column = JdbcUtils.lookupColumnName(meta_data, index);
        Object value = JdbcUtils.getResultSetValue(rs, index, Class.forName(meta_data.getColumnClassName(index)));

        bw.setPropertyValue(column, value);

      } catch (TypeMismatchException | NotWritablePropertyException | ClassNotFoundException e) {
         // Ignore
      }
    }

    return mappedObject;
  }
}


 类似资料:
  • 给出以下POJO示例:(假设所有属性都是getter和setter) 可以轻松地查询数据库(在我的例子中是postgres),并使用BeanPropertyRowMapper填充消息类列表,其中db字段与POJO中的属性匹配:(假设db表具有与POJO属性对应的字段)。 生成已填充关联用户的消息列表 用例: 最终,这些类作为序列化对象从Spring控制器传递回来,这些类被嵌套,这样得到的JSON/

  • 我有问题,需要帮助。 问题是我正在尝试使用 jdbctemplate 和映射获取查询的结果,该结果导致我的 File 类。 我的类文件包含3O个属性:10个长、字符串和日期类型的属性。 我正在执行的查询: 当执行查询时,它不会给我一个错误,一切都是正确的,但是当显示结果时,列出来为空,错误是由于我使用的查询使用别名,别名与File类的属性名称不匹配。 这就是我的问题或查询,因为我不能更改类属性的名

  • 我有一个带有用户表的标准MySql数据库。在这个表中有一个名为“isApproved”的TINYINT(4) 即使数据库中有“1”,也会返回“false”。 我如何使这个映射正确,isApproved是“1”,这应该等同于true作为布尔值。

  • 我正试图使用Spring JDBCTemplate从数据库中获取一条记录。在JdbcTemplate中,我试图通过使用类BeanPropertyRowMapper来自动化数据绑定。我的数据库表列名称类型和模型对象字段名称类型是相同的…我实现了这个API,但我没有得到预期的结果…对于int和double字段,我得到0和0.0值,尽管这些值在数据库中是不同的... 请帮助解决这个问题...我的代码如下

  • 我有这门课: 并希望在“列表”状态数组中的“卡片”数组上使用setState。以前,我在子组件中使用了cards数组,但现在我将其上移到Board类。这是我以前拥有的功能。 我如何改变它,使它现在工作,卡是在另一个数组? 我无法解决它看这些帖子: ReactJS-数组中对象键的设置状态 如何编辑状态数组中的项?

  • 我下面设置了一个名为“form”的JSP属性 这是有效的。属性“form”包含一个Java对象,它将用于进一步评估和稍后在JSP中显示。但是,我想在不事先知道表单名称的情况下以更通用的方式使用它——它可以被命名为例如“ModelForm”而不是“buildForm”。如果我们假设我已经将变量的名称存储在JSP属性“formName”中 如何使用它来设置JSP属性“form”,如第一个代码示例中所示