1

我想考虑我的案例类的一些常见属性,比如 id 和时间戳,来编写这些通用代码。以下工作正常,但我必须在每个案例类上重复所有属性:

trait HasIdAndTimestamp {
  val id: Int
  val timestamp: Long
}
case class Client(id: Int, timestamp: Long, name: String) extends HasIdAndTimestamp
case class Order(id: Int, timestamp: Long, items: List[Int], clientId: Int) extends HasIdAndTimestamp
...

另一种选择是将这些公共字段放在 MetaData 类型的单个字段上:

case class MetaData(id: Int, timestamp: Long)
trait HasMetaData {
  val metadata: MetaData
}
case class Client(metadata: MetaData, name: String) extends HasMetaData
case class Order(metadata: MetaData, items: List[Int], clientId: Int) extends HasMetaData
...

但我真的不喜欢一直写 .metadata.id 。此外,我想使用 Slick 将这些案例类存储在数据库中,并且这种嵌套在表定义中引入了许多额外的样板。我宁愿喜欢类似以下的东西:

case class MetaData(id: Int, timestamp: Long)
case class Client(name: String) extends MetaData
case class Order(items: List[Int], clientId: Int) extends MetaData
...

其中 Client 和 Order 都具有这些 id 和时间戳 (val) 字段并相应地定义了应用/取消应用。

shapeless/scalaz 可以在这里帮助我吗?

4

1 回答 1

2

这个怎么样?

// type def for Metadata
object MetadataType{ // singleton wrapper, because type defs can't be toplevel
  type MetaData = (Int,Long)
}
import MetadataType.Metadata

// unpack using pattern matching
class HasMetaData(metadata: Metadata) {
  val (id,timestamp) = metadata
}
case class Client(metadata: MetaData, name: String) extends HasMetaData(metadata)
case class Order(metadata: MetaData, items: List[Int], clientId: Int) extends HasMetaData(metadata)

// alternative: even avoid constructor argument
trait HasMetaData {
  def metadata: Metadata
  lazy val (id,timestamp) = metadata // lazy to avoid init order probs
}
case class Client(metadata: MetaData, name: String) extends HasMetaData
case class Order(metadata: MetaData, items: List[Int], clientId: Int) extends HasMetaData

然后在 Slick 中:

...
def * = ((id,timestamp), name) <> (Client.tupled, Client.unapply)
...

不确定items: List[Int]是针对Order. 如果它是单独关联表的外键,它不应该在这里。Order Table 类旨在准确描述一个数据库表。如果要从多个表中组合数据,请将其作为 (Order,List[Int]) 类型的值在外部写入。您可以在客户端使用带有后续 groupBy 的连接或两个单独的查询来实现它。在某些时候,我们希望在 Slick 中支持这样的 groupBy,它实际上返回一个嵌套集合,但此时您必须在客户端编写它。

于 2014-03-28T19:09:06.030 回答