I’m using JDBI’s SQL Objects declarative API to map an object containing a one-to-many relationship:
class Foo { private String id; private String name; private Set<Bar> bars = new HashSet<>(); } class Bar { private String id; }
Initially it looked like a RowReducer
would be ideal:
@UseFreemarkerSqlLocator class FooQuery { @SqlQuery @RegisterBeanMapper(value = Foo.class, prefix = "f") @RegisterBeanMapper(value = Bar.class, prefix = "b") @UseRowReducer(RowReducer.class) ResultIterator<Foo> queryAll(); static class RowReducer implements LinkedHashMapRowReducer<String, Foo> { @Override public void accumulate(Map<String, Foo> map, RowView rowView) { final Foo foo = map.computeIfAbsent(rowView.getColumn("f_id", String.class), id -> rowView.getRow(Foo.class)); if (rowView.getColumn("b_id", String.class) != null) { foo.addBar(rowView.getRow(Bar.class)); } } } }
However I soon discovered that RowReducer
s don’t work with ResultIterator
s (I’m working with a large database so it’s important to be able to stream these) so now I’m reverting back to implementing a RowMapper
instead. I’d still like to use the handy BeanMapper
s built into JDBI though but I can’t figure out how to access them from within my RowMapper
implementation.
class FooRowMapper implements RowMapper<Foo> { private Foo foo = null; @Override public Foo map(ResultSet rs, StatementContext ctx) throws SQLException { String fooId = rs.getString("f_id"); if (foo == null || !foo.id.equals(fooId)) { // ideally construct using JDBI's BeanMapper similar to how we can above // in the RowReducer! foo = ??? } // same as above... Bar bar = ??? foo.addBar(bar); return foo; } }
Is it possible to easily use BeanMappers from within a RowMapper so I don’t have to manually construct the beans?
Advertisement
Answer
RowMapper<Bar> barMapper = BeanMapper.of(Bar.class) Bar bar = barMapper.map(rs, ctx); foo.addBar(bar);