我想考虑我的案例类的一些常见属性,比如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将这些案例类存储在DB中,这种嵌套在表定义中引入了许多额外的样板。我宁愿喜欢类似以下的东西:
case class MetaData(id: Int, timestamp: Long)
case class Client(name: String) extends MetaData
case class Order(items: List[Int], clientId: Int) extends MetaData
...
客户端和订单都具有这些id和timestamp(val)字段,并相应地应用/取消应用。
可以变形/斯卡拉兹帮助我吗?
答案 0 :(得分: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,它实际上返回一个嵌套集合,但此刻你必须在客户端编写它。