如何将jooq multiset的结果映射到Hashmap(Java Map)中?

How to map the result of jooq multiset into Hashmap(Java Map)?

我有以下class和查询。我想使用 multisetimages 的结果映射到 Map<String, String>(Key: OrderNumber / Value: FileKey),但我不知道该怎么做。你能帮我如何将 multiset 结果映射到 hashmap 吗?

data class User(
  val id: UUID,
  val name: String,
  val images: Map<String, String>?
)
@Repository
@Transactional(readOnly = true)
class FetchUserRepository(private val ctx: DSLContext) {
  private val user = JUser.USER
  private val userImage = JUserImage.USER_IMAGE 

  override fun fetch(): List<User> {
    return ctx.select(
      user.ID,
      user.NAME,
      multiset(
        select(userImage.ORDER_NUMBER.cast(String::class.java), userImage.FILE_KEY)
          .from(userImage)
          .where(userImage.USER_ID.eq(user.ID))
      ).convertFrom { r -> r.map(mapping(???)) } // I'm not sure how to map the result to hashmap
    )
      .from(user)
      .fetchInto(User::class.java)
  }

jOOQ 3.16解决方案

您的 multiset() 表达式的类型是 Result<Record2<String, String>>, so you can use the Result.intoMap(Field, Field) method, or even Result.collect(Collector) using the Records.intoMap() 收集器,这样可以避免重复字段名称:

{ r -> r.collect(Records.intoMap()) }

I've explained this more in detail in a blog post, here.

jOOQ 3.17解决方案

事实上,这看起来非常有用和强大,让我们使用一些扩展(位于 jOOQ-kotlin 扩展模块)在现有 API 之上添加一些便利:

// New extension functions, e.g.
fun <R : Record, E> Field<Result<R>>.collecting(collector: Collector<R, *, E>)
  = convertFrom { it.collect(collector) }

fun <K, V> Field<Result<Record2<K, V>>>.intoMap(): Field<Map<K, V>> 
  = collecting(Records.intoMap())

// And then, you can write:
multiset(...).intoMap()

功能请求在这里:https://github.com/jOOQ/jOOQ/issues/13538

除了 Lukas 的回答,我还想提供一个替代选项 jsonObject & jsonObjectAgg

此查询的结果将以 JSON 格式返回,并且可以通过 Jackson 或其他方式轻松地将其投影到目标 class。 (当涉及到目标中的嵌套集合时,这是一个非常强大的功能class)

我相信这是 jOOQ 最酷的功能之一,因为 MULTISET :)

data class User(
  val id: UUID,
  val name: String,
  val images: Map<String, String>?
)

@Repository
@Transactional(readOnly = true)
class FetchUserRepository(private val ctx: DSLContext) {
  private val user = JUser.USER
  private val userImage = JUserImage.USER_IMAGE

  override fun fetch(): List<User> {
    return ctx.select(
      jsonObject(
        key("id").value(user.ID),
        key("name").value(user.NAME),
        key("images").value(
          field(
            select(
              jsonObjectAgg(
                userImage.ORDER_NUMBER.cast(String::class.java),
                userImage.FILE_KEY
              )
            )
              .from(userImage)
              .where(userImage.USER_ID.eq(user.ID))
          )
        )
      )
    )
      .from(user)
      .fetchInto(User::class.java)
  }
}