如何在R2DBC中将查询结果映射到含List类型字段的实体?
解决R2DBC中关联List字段映射重复对象的问题
你的问题根源在于JOIN查询返回的每一行都会被映射成独立的Employee对象,每个对象仅包含当前行对应的单个Account。要实现合并相同Employee的Account列表,需要在Flux流中对查询结果做分组合并处理。
步骤1:补全SQL查询字段
你的SQL语句遗漏了a.employeeId字段,必须补充才能正确映射Account的employeeId属性:
SELECT e.id, e.name, e.surname, a.employeeId, a.accountNumber FROM employee e JOIN account a on e.id = a.employeeId WHERE e.id = :id
步骤2:调整映射逻辑为可变列表
原映射用List.of()创建的是不可变列表,后续无法添加元素,需要改为可变的ArrayList:
public static final BiFunction<Row, RowMetadata, Employee> EMPLOYEE_MAPPER = (row, rowMetadata) -> Employee.builder() .id(row.get("id", Long.class)) // 匹配实体类的Long类型id .name(row.get("name", String.class)) .surname(row.get("surname", String.class)) .accounts(new ArrayList<>(List.of(new Account( row.get("employeeId", String.class), row.get("accountNumber", String.class) )))) .build();
步骤3:分组合并Employee对象
在仓库方法中,通过groupBy按Employee的id分组,再用reduce合并同组内的Account列表:
public Flux<Employee> findCardByPan(Long id) { return databaseClient.sql("SELECT e.id, e.name, e.surname, a.employeeId, a.accountNumber FROM employee e JOIN account a on e.id = a.employeeId WHERE e.id = :id") .bind("id", id) .map(EMPLOYEE_MAPPER) .groupBy(Employee::getId) // 按Employee ID分组 .flatMap(group -> group.reduce((emp1, emp2) -> { // 合并两个Employee的Account列表 emp1.getAccounts().addAll(emp2.getAccounts()); return emp1; })); }
补充优化建议
- 可以在Employee实体类中直接初始化accounts为可变列表,简化映射逻辑:
private List<Account> accounts = new ArrayList<>(); - 若需处理
LEFT JOIN(Employee可能无关联Account)的场景,可在映射时判断accountNumber是否为null,避免添加空Account对象。
内容的提问来源于stack exchange,提问作者ilham
相关产品推荐
相关产品推荐

