为 Seq 提供 Get 实例

provide Get instance for Seq

例如,我有一些带有一些参数的实体和两个数据库表,代表这些实体:

 entity                 param
╔════╦═════════╗       ╔═══════════╦════════╗
║ id ║ name    ║       ║ entity_id ║ value  ║
╠════╬═════════╣       ╠═══════════╬════════╣
║ 1  ║ "One"   ║       ║ 1         ║ "aaa"  ║
║ 2  ║ "Two"   ║       ║ 1         ║ "bbb"  ║
║ 3  ║ "Three" ║       ║ 1         ║ "ccc"  ║
╚════╩═════════╝       ╚═══════════╩════════╝

还有一个 Scala 模型:

case class Entity(id: Long, name: String, params: Seq[String])

我想通过 Doobie 检索这些数据,但我不能直接对 Entity 实例进行检索,因为 params 是一个字符串序列,而不是只是字符串:

val sql = sql"select e.id, e.name, p.value from entity e left join param p on e.id = p.entity_id"

sql.query[Entity].to[Seq]   //Error Cannot find or construct a Read instance for type: Entity

有什么技巧可以为 Seq 提供 Get 实例吗?

如果没有,有什么办法,Doobie提供检索这样的数据:

  1. 写基元而不是 Entity 类型:
    sql.query[(Long, String, String)].to[Seq] 并将此元组序列组合到 Entity 实例。
    可能不方便,因为表可能有很多列,是什么导致将这个长元组复制粘贴到每个新查询中。
  2. 将此基元组合成另一种情况 类:
    case class EntityRow(id: Long, name: String)
    case class ParamRow(value: String)
    sql.query[(EntityRow, ParamRow)].to[Seq] 并组成 Entity 实例,如 1..
  3. 类似于2.,但使用HNil
    val entity = Long :: String :: HNil
    val param = String :: HNil
    sql.query[entity ++ param].to[Seq] 并组成 Entity 实例,如 1..
    我不知道这种方式有什么优点或缺点,因为 shapeless 对我来说是个新事物。
  4. 使用两个单独的查询检索数据:
    val entities = sql"select id, name from entity".query[EntityRow].to[Seq]
    val params = sql"select value from param".query[ParamRow].to[Seq]
    可能不如通过单个查询那么性能。
  5. 还有别的方法吗?

谢谢。

您的案例 class Entity 期望 params 与 id 和 name 列组合在一起作为字符串列表,
而 sql 查询 select e.id, e.name, p.value from entity e left join param p on e.id = p.entity_id 将 return 包含 id、名称和值的行

joined entity
╔════╦═════════╦════════╗
║ id ║ name    ║ value  ║
╠════╬═════════╬════════╣
║ 1  ║ "One"   ║ "aaa"  ║
║ 1  ║ "One"   ║ "bbb"  ║
║ 1  ║ "One"   ║ "ccc"  ║
║ 2  ║ "Two"   ║        ║
║ 3  ║ "Three" ║        ║
╚════╩═════════╩════════╝

这不是您想要的。 为此,我们需要重写 sql 查询,如下所示

val entities = sql"select e.id, e.name, GROUP_CONCAT(p.value SEPARATOR ',') as params from entity e left join param p on e.id = p.entity_id group by e.id, e.name".query[Entity]  

现在您可以轻松地将 sql 查询输出映射到您的案例 class。