Slick 3.1 - Получение подмножества столбцов как класса case
Я работаю с Slick 3.1.1, и проблема в том, что в некоторых случаях я хочу опустить некоторые столбцы, которые довольно тяжелы и по-прежнему материализуют этот поднабор столбцов как класс case.
Рассмотрим следующее определение таблицы:
class AuditResultTable(tag: Tag) extends Table[AuditResult](tag, AuditResultTableName) {
def auditResultId: Rep[Long] = column[Long]("AuditResultId", O.PrimaryKey, O.AutoInc)
def processorId: Rep[Long] = column[Long]("ProcessorId")
def dispatchedTimestamp: Rep[Timestamp] = column[Timestamp]("DispatchedTimestamp", O.SqlType("timestamp(2)"))
def SystemAOutput: Rep[Array[Byte]] = column[Array[Byte]]("SystemAOutput", O.SqlType("LONGBLOB"))
def SystemBOutput: Rep[Array[Byte]] = column[Array[Byte]]("SystemBOutput", O.SqlType("LONGBLOB"))
def isSuccessful: Rep[Boolean] = column[Boolean]("IsSuccessful")
def * : ProvenShape[AuditResult] = (processorId, dispatchedTimestamp, systemAOutput, systemBOutput, isSuccessful, auditResultId) <>
(AuditResult.tupled, AuditResult.unapply)
}
val auditResults = TableQuery[AuditResultTable]
Соответствующий класс case:
case class AuditResult (
ProcessorId: Long,
DispatchedTimestamp: Timestamp,
SystemAOutput: Array[Byte],
SystemBOutput: Array[Byte],
IsSuccessful: Boolean,
AuditResultId: Long = 0L
)
И, наконец, запрос доступа к данным:
def getRecentFailedAuditsQuery(): Query[AuditResultTable, AuditResult, Seq] = {
auditResults.filterNot(r => r.isSuccessful)
}
Я рассмотрел и рассмотрел представленные варианты в этом (устаревшем) ответе и других:
- Имея разную проекцию, чем проекция по умолчанию, которая сопоставляется с "легкой версией
AuditResult
, например AuditResultLight
, которая опускает эти столбцы, несмотря на мои лучшие усилия, я не мог сделать эту работу - я чувствую, что это должно быть правильным подходом - как только у меня была" рабочая "проекция, у меня все еще была ошибка Slick" Нет соответствующей формы. Слик не знает, как сопоставить данные типы "
- Построение иерархии классов с абстрактным классом
AuditResultTableBase
и двумя вытекающими из него классами - тем, который добавляет "тяжелые" столбцы, а один без них, как с их соответствующими проекциями по умолчанию, так и с классами. Это работает хорошо, но подход кажется неправильным и требует относительно большого изменения кода для такой легкой вещи.
- Материализация кортежей вместо классов классов - это, конечно, будет работать, но я хочу, чтобы уровень доступа к данным был строго типизирован.
Какова идиоматическая/лучшая практика для Slick 3.1 для этой проблемы? Могу ли я использовать пользовательскую проекцию для этого, и если да, то что бы это выглядело для этого конкретного примера/запроса с SystemAOutput
и SystemBOutput
, являющимися тяжелыми столбцами, которые я хочу пропустить?
Ответы
Ответ 1
У меня была аналогичная проблема! Вы должны определить форму! С помощью документации мне удалось сделать этот подход с использованием "легкого" класса case.
Сначала определите более простой класс:
case class AuditResultLight(
ProcessorId: Long,
DispatchedTimestamp: Timestamp,
IsSuccessful: Boolean,
AuditResultId: Long = 0L
)
Затем вам нужно создать отмененную версию класса case:
case class AuditResultLightLifted(
ProcessorId: Rep[Long],
DispatchedTimestamp: Rep[Timestamp],
IsSuccessful: Rep[Boolean],
AuditResultId: Rep[Long]
)
Кроме того, вам нужен неявный объект (Shape), чтобы рассказать о том, как сопоставить один в другом:
implicit object AuditResultLightShape
extends CaseClassShape(AuditResultLightLifted.tupled, AuditResultLight.tupled)
Теперь вы можете определить запрос, который возвращает AuditResultLight (не точно проецирование, но насколько я понимаю, он работает аналогично):
val auditResultsLight = auditResults.map(r => AuditResultLightLifted(r.ProcessorId, r.DispatchedTimestamp, r.IsSuccessful, r.AuditResultId))
Затем вы можете определить функцию, которая возвращает неудачные аудиты в легкой форме:
def getRecentFailedAuditsQuery(): Query[AuditResultTable, AuditResultLight, Seq] = {
auditResultsLight.filterNot(r => r.isSuccessful)
}
Суть с кодом: https://gist.github.com/wjur/93712a51d392d181ab7fc2408e4ce48b
Код компилируется и выполняется, но в моем случае проблема заключается в том, что моя IDE (IntelliJ) сообщает Query[Nothing, Nothing, scala.Seq]
для auditResultsLight
. Я получаю синтаксические ошибки всякий раз, когда я использую auditResultsLight
и ссылаюсь на поле AuditResultLight
в запросе. Однако из-за этого, в конце концов, я решил использовать второй предложенный вами подход (тот, который содержит абстрактную таблицу). Почти такой же код, но с поддержкой IDE.