我遇到了弗拉德在推特上提到的一个堆栈溢出问题。 如何在春季 jdbc 模板中映射一对多关系。
第一个问题是,使用 RowMapper 接口实际上只能映射一对一的关系,因为它假定一个 ResultSet 行将映射到一个对象。
正如RowMapper接口所述:
用于在每行的基础上映射结果集的行... 此接口执行将每行映射到结果对象的实际工作
为了能够映射通常使用联接恢复的一对多,您需要能够将多行聚合到一个对象中。ResultSetExtractor将允许跨 Merge 工作,然后返回一个集合。ResultSet
对于结果集处理,RowMapper 通常是一个更简单的选择,它每行映射一个结果对象,而不是整个结果集映射一个结果对象。
您可以使用根对象 ID 更改来检测新对象何时启动。 代码看起来像。
List<User> users = new ArrayList<>();
User currentUser = null;
while(rs.next()) {
long id = rs.getLong("id");
if (currentUser == null) { // initial object
currentUser = mapUser(rs);
} else if (currentUser.getId() != id) { // break
users.add(currentUser);
currentUser = mapUser(rs);
}
currentUser.addRole(mapRole(rs));
}
if (currentUser != null) { // last object
users.add(currentUser);
}
这还不错,但随着您添加更多联接,复杂性会迅速增加。
幸运的是,SimpleFlatMapper已经解决了这个问题。 您需要做的就是使用JdbcTemplateMapperFactory 创建 aage。ResultSetExtractor
private final ResultSetExtractor<List<User>> resultSetExtractor =
JdbcTemplateMapperFactory
.newInstance()
.addKeys("id") // the column name you expect the user id to be on
.newResultSetExtractor(User.class);
您现在可以使用它来映射您的一对多。resultSetExtractor
String query =
"SELECT u.id as id, u.username, u.id as adverts_id, ad.text as adverts_text"
+ "FROM user u LEFT OUTER JOIN advert ad ON ad.account_id = ac.id order by id "
List<User> results = template.query(query, resultSetExtractor);
请注意,sfm 使用根 id 中断作为其聚合的基础,因此查询的顺序很重要。
自6.2.0以来的更新是一个新选项允许使用无序结果集进行联接映射。unorderedJoin()
如果要将角色列表保留在用户对象之外,该怎么办?
无需使用User类和UserWithRole类,您只需将查询映射到ausing sfm元组或jOOL。Tuple2<User, List<Role>>
private final ResultSetExtractor<Tuple2<User, List<Role>>> resultSetExtractor =
JdbcTemplateMapperFactory
.newInstance()
.addKeys("id") // the column name you expect the user id to be on
.newResultSetExtractor(new TypeReference<Tuple2<User, List<Role>>> {});
然后
String query =
"SELECT u.id as id, u.username, u.id as adverts_id, ad.text as adverts_text"
+ "FROM user u LEFT OUTER JOIN advert ad ON ad.account_id = ac.id order by id "
List<Tuple2<User, List<Role>>> results = template.query(query, resultSetExtractor);
每个元组 2 都有用户及其关联的角色。
总结
您不需要使用复杂的 ORM 将 sql 查询映射到对象,即使有多个一对多关系也是如此。 SimpleFlatMapper已经为您处理了所有的复杂性,因此请放弃编写手动RowMapper,并花时间编写业务逻辑而不是样板映射代码。