У меня есть база данных, содержащая действия с отношением регистрации "один ко многим". Цель состоит в том, чтобы получить все действия со списком их регистраций.
Создавая декартовый продукт действий с регистрациями, мы получаем все необходимые данные для получения этих данных. Но я не могу найти хороший способ правильно поместить его в коллекцию scala; давайте типа: Seq[(Activity, Seq[Registration])]
case class Registration(
id: Option[Int],
user: Int,
activity: Int
)
case class Activity(
id: Option[Int],
what: String,
when: DateTime,
where: String,
description: String,
price: Double
)
Предполагая, что соответствующие гладкие таблицы и табличные запросы существуют, я бы написал:
val acts_regs = (for {
a <- Activities
r <- Registrations if r.activityId === a.id
} yield (a, r))
.groupBy(_._1.id)
.map { case (actid, acts) => ??? }
}
Но я не могу сделать соответствующее сопоставление. Каков идиоматический способ сделать это? Надеюсь, это лучше, чем работать с сырым декартовым произведением...
В Скала
В коде scala это достаточно просто и будет выглядеть примерно так:
val activities = db withSession { implicit sess =>
(for {
a <- Activities leftJoin Registrations on (_.id === _.activityId)
} yield a).list
}
activities
.groupBy(_._1.id)
.map { case (id, set) => (set(0)._1, set.map(_._2)) }
Но это кажется довольно неэффективным из-за ненужных экземпляров Activity, которые создаст для вас сопоставитель таблиц. И не очень элегантно выглядит...
Получение подсчета регистраций
Метод in scala еще хуже, когда интересует только количество регистраций, например:
val result: Seq[Activity, Int] = ???
В Слике
Моя лучшая попытка в slick выглядела бы так:
val activities = db withSession { implicit sess =>
(for {
a <- Activities leftJoin Registrations on (_.id === _.activityId)
} yield a)
.groupBy(_._1.id)
.map { case (id, results) => (results.map(_._1), results.length) }
}
Но это приводит к ошибке, что slick не может отображать данные типы в строке «map».