我正在尝试使用 Slick 来查询多对多关系,但我遇到了各种错误,最突出的是“不知道如何将 (User, Skill) 解压到 T 并打包到G”。
表的结构类似于以下内容:
case class User(val name: String, val picture: Option[URL], val id: Option[UUID])
object Users extends Table[User]("users") {
def name = column[String]("name")
def picture = column[Option[URL]]("picture")
def id = column[UUID]("id")
def * = name ~ picture ~ id.? <> (User, User.unapply _)
}
case class Skill(val name: String, val id: Option[UUID])
object Skills extends Table[Skill]("skill") {
def name = column[String]("name")
def id = column[UUID]("id")
def * = name ~ id.? <> (Skill, Skill.unapply _)
}
case class UserSkill(val userId: UUID, val skillId: UUID, val id: Option[UUID])
object UserSkills extends Table[UserSkill]("user_skill") {
def userId = column[UUID]("userId")
def skillId = column[UUID]("skillId")
def id = column[UUID]("id")
def * = userId ~ skillId ~ id.? <> (UserSkill, UserSkill.unapply _)
def user = foreignKey("userFK", userId, Users)(_.id)
def skill = foreignKey("skillFK", skillId, Skills)(_.id)
}
最终,我想要实现的是某种形式
SELECT u.*, group_concat(s.name) FROM user_skill us, users u, skills s WHERE us.skillId = s.id && us.userId = u.id GROUP BY u.id
但在我花时间尝试让 group_concat 也能正常工作之前,我一直在尝试生成更简单的查询(我相信它仍然有效......)
SELECT u.* FROM user_skill us, users u, skills s WHERE us.skillId = s.id && us.userId = u.id GROUP BY u.id
我已经尝试了各种 scala 代码来生成这个查询,但是导致上面形状错误的一个例子是
(for {
us <- UserSkills
user <- us.user
skill <- us.skill
} yield (user, skill)).groupBy(_._1.id).map { case(_, xs) => xs.first }
同样,以下会产生关于“用户”而不是“(用户,技能)”的打包错误
(for {
us <- UserSkills
user <- us.user
skill <- us.skill
} yield (user, skill)).groupBy(_._1.id).map { case(_, xs) => xs.map(_._1).first }
如果有人有任何建议,我将不胜感激:我今天和昨天大部分时间都在搜索 google/google 组以及 slick 源,但我还没有解决方案。
(另外,我使用的是 postgre,所以 group_concat 实际上是 string_agg)
编辑
所以看起来当使用 groupBy 时,映射的投影被应用,因为像
(for {
us <- UserSkills
u <- us.user
s <- us.skill
} yield (u,s)).map(_._1)
工作正常,因为 _._1 给出了用户类型,它有一个形状,因为用户是一个表。然而,当我们调用 xs.first 时(就像我们调用 groupBy 时所做的那样),我们实际上得到了一个映射的投影类型 (User, Skill),或者如果我们先应用 map(_._1),我们得到了 User 类型,这不是用户!据我所知,没有 User 作为混合类型的形状,因为定义的唯一形状是用于 Shape[Column[T], T, Column[T]] 和表 T <: TableNode, Shape[T , NothingContainer#TableNothing, T] 在 slick.lifted.Shape 中定义。此外,如果我做类似的事情
(for {
us <- UserSkills
u <- us.user
s <- us.skill
} yield (u,s))
.groupBy(_._1.id)
.map { case (_, xs) => xs.map(_._1.id).first }
我收到“NoSuchElementException:找不到键:@1515100893”形式的奇怪错误,其中数字键值每次都会更改。这不是我想要的查询,但它仍然是一个奇怪的问题。