I have two records correspondent to two different tables (recordA, tableA, recordB and tableB). TableA and TableB have the same column's names and same types. How can I select then using Jooq and map the result to the different records?
I've tried this approach:
fun findEntitiesByGroupId(groupId: UUID): ResultData {
val entityAQuery = DSL.using(configuration)
.selectFrom(ENTITY_A)
.where(ENTITY_A.GROUP_ID.eq(groupId))
val entityBQuery = DSL.using(configuration)
.selectFrom(ENTITY_B)
.where(ENTITY_B.GROUP_ID.eq(groupId))
val entityA = mutableListOf<EventHistory>()
val entityB = mutableListOf<EventHistory>()
entityAQuery.unionAll(entityBQuery).forEach {
when (it) {
is EntityARecord -> entityA.add(mapEntityA(it))
is EntityBRecord -> entityB.add(mapEntityB(it))
else -> throw AssertionError("Invalid entity type")
}
}
return ResultData(entityA, entityB)
}
I'm getting the compile error in unionAll
method:
Type mismatch.
Required:
Select<out EntityARecord!>!
Found:
SelectConditionStep<EntityBRecord!>
I didn't find any Jooq documentation about this union scenario, just for cases where we have the same record type.
The two types aren't compatible in Java / Kotlin, so you cannot use selectFrom(table)
the way you're doing. You could just use select().from(table)
instead, removing row type safety from the query, or alternatively, list all columns explicitly.
It's not possible for jOOQ to automatically map rows originating from UNION
or similar SQL operators to the "correct" mapper. I've written an entire blog post on this topic to illustrate the details of why this is impossible:
In short, there's no way for jOOQ to know which record belongs to which UNION ALL
subquery, automatically. As such, jOOQ will only ever consider the row type (and associated converters / mappers) of the first UNION ALL
subquery.
You can, however, add a discriminator column to your unions and make the decision yourself based on that, e.g.:
SELECT a.*, 'a' AS discriminator
FROM a
UNION ALL
SELECT b.*, 'b' AS discriminator
FROM b
And then, e.g.:
.forEach {
when (it["discriminator"]) {
"a" -> entityA.add(mapEntityA(it))
"b" -> entityB.add(mapEntityB(it))
else -> throw AssertionError("Invalid entity type")
}
}