Scala 案例类继承是被禁止的,但如何从库中建模依赖关系?

Scala 案例类继承是被禁止的,但如何从库中建模依赖关系?,scala,playframework,playframework-2.0,Scala,Playframework,Playframework 2.0,我有三个不同的Scala项目,其中一个只包含在其他两个Scala项目中使用的模型(以下称为库)。三个项目中的一个是PlayWeb应用程序,我希望将来自MongoDB库的模型持久化(代码驻留在PlayApp中) 因此,在我的库中,我有以下模型: case class MyUser(id: UUID = UUID.randomUUID(), timestamp: Instant = Instant.now, name: String) 要在我的Play app中持久保存MyUser的实例,我通常会

我有三个不同的Scala项目,其中一个只包含在其他两个Scala项目中使用的模型(以下称为库)。三个项目中的一个是PlayWeb应用程序,我希望将来自MongoDB库的模型持久化(代码驻留在PlayApp中)

因此,在我的库中,我有以下模型:

case class MyUser(id: UUID = UUID.randomUUID(), timestamp: Instant = Instant.now, name: String)
要在我的Play app中持久保存
MyUser
的实例,我通常会使用以下模型:

case class MyUser(var _id: Option[BSONObjectID] = None,
                   id: UUID,
                   timestamp: Instant,
                   name: String,
                   var created: Option[DateTime] = None,
                   var updated: Option[DateTime] = None
                  ) extends Temporal
现在,我正在寻找一种方法,将我的库的
MyUser
变形为我的Play app中的相应类,因此我想我会这样做:

case class MyUser(var _id: Option[BSONObjectID] = None,
                   var created: Option[DateTime] = None,
                   var updated: Option[DateTime] = None
                  ) extends lib.MyUser with Temporal
case class MyUser(var _id: Option[BSONObjectID] = None,
                   user: lib.MyUser,
                   var created: Option[DateTime] = None,
                   var updated: Option[DateTime] = None
                  ) extends Temporal
但是,现在我得到了以下错误:

禁止个案继承。要克服此限制,请使用提取器在非叶节点上进行模式匹配

我想做这样的事情:

case class MyUser(var _id: Option[BSONObjectID] = None,
                   var created: Option[DateTime] = None,
                   var updated: Option[DateTime] = None
                  ) extends lib.MyUser with Temporal
case class MyUser(var _id: Option[BSONObjectID] = None,
                   user: lib.MyUser,
                   var created: Option[DateTime] = None,
                   var updated: Option[DateTime] = None
                  ) extends Temporal

如何以正确的方式进行设计?

首先,错误告诉您的是,对于已扩展的类,不应使用
case类。它所说的提取器基本上是,如果需要在父类上进行模式匹配(这就是
case类
case
的来源,简单的模式匹配),您可以随时为其编写自定义提取器

但是,这不适用于您的案例,因为您无法更改lib公开
case类的事实

另一个解决方案是考虑两个类之间没有继承关系。实际上,一个是用户的表示,而另一个是包含用户的存储单元的表示。看来你提出的解决方案终究还是有意义的

不过,无论是在序列化对象(在Mongo中)还是在JVM类中,添加一个字段似乎都很麻烦,您需要始终执行
mongoUser.user
才能从
MyUser
获取
lib.MyUser

一个优雅的(IMHO)解决方案是保留此字段
user:lib.MyUser
,但要让序列化将此字段展平到BSON对象的顶层,以便序列化的
MyUser
看起来像

{
  _id: ObjectId(_),
  id: 123456789abc-1234-1234-1234,
  ...
}
就像您继承了
lib.MyUser
的字段一样

反序列化

现在,无论何时,只要您想从Mongo获取
lib.MyUser
,仅用于读取目的,就可以直接以这种格式对其进行反序列化,而忽略添加的字段。但是,如果需要对其进行一些更新,则必须将其反序列化为
MyUser
,才能更新此特定的BSON文档

scala使用情况

当您将对象反序列化为
MyUser
(例如,用于更新)时,您可能仍然希望能够轻松访问
lib.MyUser
中公开的所有字段,而不必每次都访问字段
user
。这可以通过隐式转换完成

泛化

顺便说一句,您可以对任何要序列化的对象执行此操作,以通用方式

总而言之

case class MongoRepr[T](_id: Option[BSONObjectId]
                         value: T,
                         created: Option[DateTime],                             
                         updated: Option[DateTime])

object MongoRepr {
  //implement flattened (de)serialization, this depends on your
  // mongo driver and what you're using for serialization (JSON/BSON)
  def handler[T](implicit handlerT: BSONHandler[T]): BSONHandler[MongoRepr[T]] = ???

 implicit def toValue[T](repr: MongoRepr[T]): T = repr.value
}

您是否愿意放弃
lib.MyUser
上的
case类
构造?嗯,我更愿意保留
case类
构造。从设计角度来看,有什么更好的方法:向
MyUser
添加一个新字段,该字段保存
lib.MyUser
,用作包装器或继承?