如何覆盖 case class 属性并避免重复存储?

How to override a case class attribute and avoid duplicated storage?

我有一个用例可以利用 case class 属性覆盖,如果这在 Scala 2 中可行的话。12.x。我的用例如下: Play-Silhouette (P-S) 中有多个案例 classes LoginInfo 图书馆建立在:

case class LoginInfo(providerID: String, providerKey: String)

如果生活是完美的,这些将是特征而不是大小写 classes 但是好吧,现在在一个重新使用 P-S 的项目中我想设计我的数据库,自定义 Slick 代码生成器并为那些 P-S 案例获取 Slick-mapped 数据库友好定义 classes 例如

case class LoginInfoRow(id: Int, override val providerID: String, override val providerKey: String, modified: Option[java.sql.Timestamp] = None) 
  extends com.mohiva.play.silhouette.api.LoginInfo(providerID, providerKey)

这种方法可以让我将我的 Slick-persistence 专业 LoginInfoRow 无缝地插入到 P-S 框架中。请注意,这是使用 Slick + 我的自定义生成器更改从数据库自动生成的。上面的 LoginInfoRow 定义导致编译错误:

[error] /home/skywalker/code/play-silhouette-seed/app/models/generated/Tables.scala:29:14: case class LoginInfoRow has case ancestor com.mohiva.play.silhouette.api.LoginInfo, but case-to-case inheritance is prohibited. To overcome this limitation, use extractors to pattern match on non-leaf nodes.
[error]   case class LoginInfoRow(id: Int, override val providerID: String, override val providerKey: String, modified: Option[java.sql.Timestamp] = None) extends com.mohiva.play.silhouette.api.LoginInfo(providerID, providerKey)
[error]              ^
[error] one error found
[error] (Compile / compileIncremental) Compilation failed
[error] Total time: 3 s, completed May 25, 2019 12:06:43 PM

一个可能的解决方案是为这两个属性使用不同的名称,但是从 LoginInfoRow 的界面来看,使用哪个属性会让人感到困惑?而且它还会重复存储。

此编译器建议的替代方案是什么 To overcome this limitation, use extractors to pattern match on non-leaf nodes.

您可以为这种情况编写隐式或显式转换器。

隐式转换器:

implicit def loginInfoRowToLoginInfo(loginInfoRow: LoginInfoRow): LoginInfo = {
  LoginInfo(loginInfoRow.providerID, loginInfoRow.providerKey)
}

显式转换器:

case class LoginInfoRow(
  id: Int,
  providerID: String,
  providerKey: String,
  modified: Option[java.sql.Timestamp] = None
) {
  def toSilhouette: LoginInfo = {
    LoginInfo(providerID, providerKey)
  }
}

或两者兼而有之。