How to select autogenerated record and additional data with joining in jooq?
Suppose you have two tables, foo
and bar
and the table that matches foo
for the allowed bar
s:
foo bar
+----+-------+ +----+-------+
| id |fooName| | id |barName|
+------------+ +----+-------+
| 1 | aa | | 10 | xx |
| 2 | bb | | 11 | yy |
| 3 | cc | | 12 | zz |
+------------+ +----+-------+
n: m The ratio between foo
andbar
foo_x_bar
+--------+--------+
| foo_id | bar_id |
+-----------------+
| 1 | 10 |
| 1 | 11 |
| 2 | 11 |
| 3 | 12 |
+-----------------+
Now, given any foo.id
(say 1
), I want a list of everyone bar
and whether they are applicable for foo.id
1
. I can do it with this SQL:
SELECT bar.id, bar.barName, foo_x_bar.foo_id
FROM bar LEFT OUTER JOIN foo_x_bar
ON bar.id = foo_x_bar.bar_id AND foo_x_bar.foo_id = 1;
This gives me the following output:
+--------+-------------+------------------+
| bar.id | bar.barName | foo_x_bar.foo_id |
+--------+-------------+------------------+
| 10 | xx | 1 |
| 11 | yy | 1 |
| 12 | zz | null |
+--------+-------------+------------------+
Ie: I get the full list bar
and I know what they are referring foo
to id
1
. (All lines with null
for are foo_id
not referenced)
So now (finally) to my question: how to achieve this with jooq, so I BarRecord
end up with nice jooq autogenerates classes for me. This is how I guessed it:
List<Record3<Long, String, Long>> result =
create.select(BAR.ID, BAR.BARNAME, FOO_X_BAR.FOO_ID)
.from(BAR).leftOuterJoin(FOO_X_BAR)
.on(BAR.ID.eq(FOO_X_BAR.BAR_ID))
.and(FOO_X_BAR.FOO_ID.eq(fooId))
.fetch();
This is all well and good, but if it bar
has a lot more columns it gets tedious and I would like to use the autogeneration of the BarRecord
jooq class for me .
How can I get it Record2<BarRecord, Long>
instead?
=============== Edit ==============
Based on the correct answer below, this is the complete code we came across:
public static class BarMapper
implements RecordMapper<Record, Pair<BarRecord, Boolean>> {
//the boolean indicates if a matching FOO is present
return new Pair<BarRecord, Boolean>(
record.into(BAR),
record.getValue(FOO_X_BAR.FOO_ID) != null);
}
public List<Pair<BarRecord, Boolean>> selectBarsForFooId(final long fooId) {
create.select(BAR.fields()).select(FOO_X_BAR.FOO_ID)
.from(BAR).leftOuterJoin(FOO_X_BAR)
.on(BAR.ID.eq(FOO_X_BAR.BAR_ID))
.and(FOO_X_BAR.FOO_ID.eq(fooId))
.fetch(new BarMapper());
}
source to share
You can write:
create.select(BAR.fields())
.select(FOO_X_BAR.FOO_ID)
BAR.fields()
more or less the same as BAR.*
in SQL.
Currently (as of jOOQ 3.4) it is not possible to create nested records in your result via the jOOQ API. This is the pending feature request:
To map (partial) records to a well-typed one BarRecord
, you can simply callRecord.into(Table)
BarRecord bar = Record.into(BAR);
source to share