Внутреннее соединение не работает в Slick

Не могли бы вы сказать мне, почему я не получаю внутреннее соединение, которое я ожидаю получить?

У меня есть следующие таблицы

case class Ability(id: UUID, can: Boolean, verb: String, subject: String, context: String)

object Abilities extends Table[Ability]("abilities"){
  def id = column[UUID]("id", O.PrimaryKey)
  def can = column[Boolean]("is_can")
  def verb = column[String]("verb")
  def subject = column[String]("subject")
  def context = column[String]("context")

  def * = id ~ can ~ verb ~ subject ~ context <> (Ability, Ability.unapply _)
}

case class Role(id: UUID, name : String)

object Roles extends Table[Role]("roles"){
  def id = column[UUID]("id", O.PrimaryKey)
  def name = column[String]("name")

  def * = id ~ name <> (Role, Role.unapply _)
}

// And join table
case class AbilityRelationship(owner_id: UUID, obj_id: UUID, is_role: Boolean)

object AbilitiesMapping extends Table[AbilityRelationship]("abilities_mapping"){
  def owner_id = column[UUID]("owner_id")
  def obj_id = column[UUID]("obj_id")
  def is_role = column[Boolean]("is_role")

  def * = owner_id ~ obj_id ~ is_role <> (AbilityRelationship, AbilityRelationship.unapply _)
}

Что я хочу сделать, так это получить список объектов Ability для конкретного владельца (будь то пользователь или роль). Итак, следуя документации, я написал для нее следующий запрос на соединение

val some_id = role.id
val q2 = for {
  a <- Abilities
  rel <- AbilitiesMapping
  if rel.owner_id === some_id.bind
} yield (a)

Но q2.selectStatement возвращает для него совершенно неверный запрос. В моем случае это select x2."id", x2."is_can", x2."verb", x2."subject", x2."context" from "abilities" x2, "abilities_mapping" x3 where x3."owner_id" = ?.

Как это должно быть реализовано?

Спасибо.


person expert    schedule 23.05.2013    source источник


Ответы (3)


Ну, после нескольких попыток я это сделал

  val innerJoin = for {
    (a, rel) <- Abilities innerJoin AbilitiesMapping on (_.id === _.obj_id) if rel.owner_id === some_id.bind
  } yield a

Но чувак... документация typesafe действительно очень слаба для новичков.

person expert    schedule 23.05.2013
comment
важно использовать, если вместо добавления его в условие включения - person slckin; 01.11.2013

Попробуйте что-то вроде:

val q2 = for {
  a <- Abilities
  rel <- AbilitiesMapping
  if a.id == rel.obj_id && rel.owner_id === some_id.bind
} yield (a)

Кстати, вы знаете, что можете аннотировать свои внешние ключи в объектах таблицы, верно?

person pedrofurla    schedule 23.05.2013
comment
Но в моем случае мне не нужна информация от Role. У меня есть его идентификатор в some_id. - person expert; 23.05.2013
comment
Теперь я вижу, что вы хотели. Я перепишу свой запрос. - person pedrofurla; 23.05.2013
comment
Да, я могу аннотировать внешние ключи, но я не уверен, что смогу сделать это в моем случае с помощью Slick, потому что внешний ключ может ссылаться на разные объекты в зависимости от is_role. - person expert; 24.05.2013

Пытался сделать это как комментарий к ответу Руслана, но у меня просто не хватает сил джедая:

Можете ли вы попробовать, работает ли эта версия без сахара?

val rightSide = AbilitiesMapping.filter(_.owner_id === some_id)    
val innerJoin = (Abilities innerJoin (rightSide) on (
  (l,r) => (l.id === r.obj_id)
).map { case (l, r) => l }
person critium    schedule 05.03.2014