保理案例类属性,是否可以绕过案例类扩展的限制?

时间:2014-03-28 16:36:57

标签: scala slick scalaz case-class shapeless

我想考虑我的案例类的一些常见属性,比如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)字段,并相应地应用/取消应用。

可以变形/斯卡拉兹帮助我吗?

1 个答案:

答案 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,它实际上返回一个嵌套集合,但此刻你必须在客户端编写它。