JDBI 3使用Bean Mapper时嵌套对象为null的解决方法
解决JDBI3中嵌套对象@Nested映射为null的问题
问题诊断
你当前分别注册了Child和Parent的BeanMapper,但JDBI不会自动将两个Mapper关联为嵌套对象,@Nested注解需要明确指定嵌套字段的前缀映射规则才能生效。
修复方案
方案一:配合@Nested指定前缀(推荐)
修改Child类的@Nested注解,添加对应Parent表字段的前缀标识,同时移除单独注册的Parent BeanMapper:
修改后的Models.kt
import org.jdbi.v3.core.mapper.Nested import java.time.Instant data class Child( var id: Int = -1, @Nested("p") // 指定前缀,对应SQL中parent表字段的别名前缀 var parent: Parent? = null, var created: Instant? = null ) data class Parent( var id: Int = -1, )
修改后的ChildRepo.kt
import org.jdbi.v3.sqlobject.config.RegisterBeanMapper import org.jdbi.v3.sqlobject.statement.SqlQuery @SqlQuery(""" SELECT c.id as c_id, c.created as c_created, p.id as p_id FROM child as c INNER JOIN parent p on p.id = c.parent_id WHERE c.id = :id """) @RegisterBeanMapper(value = Child::class, prefix = "c") // 移除单独的Parent Mapper注册,@Nested会自动处理嵌套映射 operator fun get(id: Int): Child?
原理说明
@Nested("p")告诉JDBI:所有前缀为p_的查询结果字段,都要映射到parent对象的对应属性中(比如p_id对应parent.id)- 只需要注册外层
Child的BeanMapper即可,JDBI会通过@Nested的配置自动解析嵌套的Parent对象
方案二:使用JoinRowMapper(备选)
如果需要保留两个Mapper的注册,可以使用JoinRowMapper手动关联,但写法更繁琐:
import org.jdbi.v3.sqlobject.config.RegisterRowMapper import org.jdbi.v3.core.mapper.JoinRowMapper // 在Repo接口上注册JoinRowMapper @RegisterRowMapper(JoinRowMapper::class) @SqlQuery(""" -- 同之前的SQL """) @RegisterBeanMapper(value = Child::class, prefix = "c") @RegisterBeanMapper(value = Parent::class, prefix = "p") operator fun get(id: Int): Child? { // 手动从JoinRow中提取Child和Parent对象,组装后返回 val row = handle.createQuery(sql).bind("id", id).mapTo(JoinRow::class.java).one() val child = row.get(Child::class.java) val parent = row.get(Parent::class.java) child.parent = parent return child }
注意事项
- 确保SQL中嵌套对象的字段别名前缀和
@Nested指定的名称完全一致(比如p_对应@Nested("p")) - 避免同时注册外层和内层的BeanMapper,否则JDBI无法自动关联嵌套关系
内容的提问来源于stack exchange,提问作者Simen Russnes
相关产品推荐
相关产品推荐

