JDBCTemplate set nested POJO with BeanPropertyRowMapper
给定以下示例 POJO 的:(假设所有属性的 Getters 和 Setters)
class User {
String user_name;
String display_name;
}
class Message {
String title;
String question;
User user;
}
人们可以很容易地查询数据库(在我的例子中是postgres),并使用BeanPropertyRowMapper填充Messeg类列表,其中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用例涉及具有数十个字段的多个表。