2016-09-29 2 views
16

Я работаю с Slick 3.1.1, и проблема в том, что в некоторых случаях я хочу опустить некоторые столбцы, которые довольно тяжелы и по-прежнему материализуют это подмножество столбцов как кейс класс.Slick 3.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 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) 
} 

Я рассмотрел и посмотрел представленные варианты in this (outdated) answer и другие:

  • Имеет другую проекцию, чем проекция по умолчанию, которая соответствует «легкой версии AuditResult, например. AuditResultLight, который опускает эти столбцы, несмотря на все мои усилия, я не мог сделать эту работу. Я чувствую, что это так: должен быть правильным подходом - однажды у меня была «рабочая» проекция. У меня все еще была ошибка Slick «Нет соответствующей формы. Slick не знает, как сопоставить данные типы »
  • Построение иерархии классов с абстрактным классом AuditResultTableBase и двумя вытекающими из него классами - один, который добавляет« тяжелые »столбцы и один без них, оба с их соответствующей проекцией по умолчанию и классов случаев. Это работает хорошо, но подход кажется неправильным и требует относительно большого изменения кода для такой легкой вещи.
  • Материализация кортежей вместо классов корпуса - это, конечно, будет работать, но я хочу, чтобы уровень доступа к данным был строго типизирован.

Какая идиоматическая/лучшая практика для Slick 3.1 для решения этой проблемы? Могу ли я использовать пользовательскую проекцию для этого, и если да, то что бы это выглядело для этого конкретного примера/запроса с SystemAOutput и SystemBOutput, являющимися тяжелыми столбцами, которые я хочу опустить?

ответ

5

У меня была аналогичная проблема! Вы должны определить форму! С помощью documentation мне удалось сделать этот подход с помощью «светлой» работы класса case.

Во-первых, определить простой класс:

case class AuditResultLight(
    ProcessorId: Long, 
    DispatchedTimestamp: Timestamp, 
    IsSuccessful: Boolean, 
    AuditResultId: Long = 0L 
) 

Затем вам нужно создать поднятую версию класса случая:

case class AuditResultLightLifted(
    ProcessorId: Rep[Long], 
    DispatchedTimestamp: Rep[Timestamp], 
    IsSuccessful: Rep[Boolean], 
    AuditResultId: Rep[Long] 
) 

Кроме того, вам нужно неявный объект (форма), чтобы рассказать о том, как сопоставить друг друга:

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.

+0

Спасибо Wojciech. Я надеялся, что будет «один» явно правильный ответ, но, похоже, я не единственный, у кого проблемы. Спасибо за понимание того, как правильно реализовать форму/сопоставление для этого варианта использования (даже если IntelliJ не нравится) - щедрость - это все ваше. – BrokenGlass

Смежные вопросы