【问题标题】:Slick 3.1 - Retrieving subset of columns as a case classSlick 3.1 - 检索列子集作为案例类
【发布时间】:2017-02-08 10:08:12
【问题描述】:

我正在使用 Slick 3.1.1,问题是在某些情况下,我想省略一些相当重的列,并且仍然将该列子集具体化为案例类。

考虑下面的表定义:

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 的惯用/最佳实践是什么?我可以为此使用自定义投影吗?如果可以,这个特定示例/查询会是什么样子?SystemAOutputSystemBOutput 是我想省略的重列?

【问题讨论】:

    标签: scala slick slick-3.0


    【解决方案1】:

    我遇到了类似的问题!你必须定义形状!在documentation 的帮助下,我设法通过“轻量级”案例类工作。

    首先,定义更简单的类:

    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]
    )
    

    此外,您需要一个隐式对象(形状)来告诉 slick 如何将一个映射到另一个:

    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。

    【讨论】:

    • 谢谢 Wojciech - 我曾希望有“一个”明确正确的答案,但似乎我不是唯一一个遇到麻烦的人。感谢您对如何为这个用例正确实现形状/映射的见解(即使 IntelliJ 不喜欢它) - 赏金全是你的。
    猜你喜欢
    • 2016-03-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多