Slick 3.1 - 检索列的子集作为案例类

时间:2016-09-29 22:49:38

标签: scala slick slick-3.0

我正在使用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不知道如何映射给定的类型“
  • 使用抽象AuditResultTableBase类和从中派生的两个类构建一个类层次结构 - 一个添加“重”列,另一个不添加它们,两者都有各自的默认投影和案例类。这很好用,但这种方法看起来很错误,并且需要进行相对较大的代码更改才能实现这么简单的事情。
  • 实现元组而不是案例类 - 这当然会起作用,但我希望我的数据访问层是强类型的。

Slick 3.1解决此问题的惯用/最佳做法是什么?我是否可以为此使用自定义投影?如果是这样,对于SystemAOutputSystemBOutput这个我要忽略的重列的特定示例/查询,它会是什么样子?

1 个答案:

答案 0 :(得分:5)

我有类似的问题!你必须定义形状!在documentation的帮助下,我成功地使用&#34; light&#34;案例类工作。

首先,定义更简单的类:

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]的{​​{1}}类型。每当我使用auditResultsLight并在查询中引用auditResultsLight字段时,我都会收到语法错误。但是,正因为如此,我最终决定使用你建议的第二种方法(带有抽象表的方法)。几乎相同数量的代码,但支持IDE。