Spring Data + Jooq DSL一对多查询如何返回空关联数组而非全null对象
问题原因
你出现的返回结果包含全null地址对象的问题,根源是LEFT JOIN查询下无关联地址记录时,地址相关字段返回全null,你所使用的SimpleFlatMapper映射框架(即JdbcMapper所属类库)默认会将全null的子属性映射为对象加入集合,最终产生了不符合预期的结果。
可行解决方案
方案1:修改SimpleFlatMapper映射配置(推荐,改动最小)
SimpleFlatMapper原生提供了过滤全null子对象的配置项,仅需在构建JdbcMapperFactory时开启filteringAllNullSubObjects即可,开启后所有属性全为null的子对象不会被加入集合,无关联记录时直接返回空数组。
修改后的映射构建代码如下:
JdbcMapper<User> mapper = JdbcMapperFactory .newInstance() .addKeys("id") // 新增该行配置,过滤全null子对象 .filteringAllNullSubObjects(true) .newMapper(User.class);
该方案无需修改查询逻辑,仅改动一行配置即可实现需求,对现有代码侵入性最低。
方案2:使用Jooq原生Multiset关联查询(更优雅,适配Jooq 3.15+版本)
如果你使用的Jooq版本在3.15及以上,可以直接使用Jooq提供的multiset能力直接构造关联集合,不需要手动做JOIN后拆分映射,天然支持无关联记录时返回空集合:
public Set<User> getUserById(Set<Long> id) { return dsl.select( field("u.id", Long.class).as("id"), field("u.name", String.class).as("name"), // 嵌套查询关联的地址集合 multiset( select(field("a.id", Long.class), field("a.country", String.class), field("a.street", String.class)) .from("schema.address_table a") .where(field("a.user_id", Long.class).eq(field("u.id", Long.class))) ).as("addresses").convertFrom(r -> r.map(Records.mapping(Address::new))) ).from("schema.user_table u") .where(field("u.id").in(id)) .fetchSet(Records.mapping(User::new)); }
该方案从查询层面就避免了LEFT JOIN产生的全null记录,不需要依赖第三方映射类库,查询性能也更高。
方案3:返回结果后手动过滤
如果不想调整依赖或者Jooq版本,也可以在拿到映射后的结果后,手动过滤掉无效的全null地址对象:
try(ResultSet rs = users.fetchResultSet()) { JdbcMapper<User> mapper = JdbcMapperFactory .newInstance() .addKeys("id") .newMapper(User.class); result = mapper.stream(rs).collect(Collectors.toSet()); // 新增后处理逻辑 result.forEach(user -> { if (user.getAddresses() != null) { // 地址id为主键,主键为null即可判定为全null无效对象 List<Address> validAddresses = user.getAddresses().stream() .filter(address -> address.getId() != null) .collect(Collectors.toList()); user.setAddresses(validAddresses); } }); } catch (Exception e) { e.printStackTrace(); }
该方案逻辑最直白,不需要调整现有查询和映射配置,适合临时快速修复问题。
内容的提问来源于stack exchange,提问作者Roman Kiselev
相关产品推荐
相关产品推荐

