【问题标题】:How to override a case class attribute and avoid duplicated storage?如何覆盖案例类属性并避免重复存储?
【发布时间】:2019-10-11 17:16:46
【问题描述】:

如果在 Scala 2.12.x 中可行,我有一个用例可以利用案例类属性覆盖。我的用例如下:Play-Silhouette (P-S) 中有多个案例类,例如LoginInfo 库是基于:

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

如果生活是完美的,这些将是特征而不是案例类,但是好的,现在在一个重用 PS 的项目中,我想设计我的数据库,自定义 Slick 代码生成器并获得 Slick-mapped 数据库-那些 PS 案例类的友好定义,例如

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.是什么?

【问题讨论】:

    标签: scala slick silhouette


    【解决方案1】:

    您可以为此场景编写一个隐式或显式转换器。

    隐式转换器:

    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)
      }
    }
    

    或两者兼而有之。

    【讨论】:

    • 谢谢!那将是一个解决方案,但我发现重构为特征而不是为AuthInfo 子类型保留案例类会更干净。在许多方面更清洁:更少的复杂性,更少的开销,并防止应用程序拥有 2 倍于这些 AuthInfo 实例的数量。请记住,如果 AuthInfo 是特征,我还需要有 fromSilhouette 等价物,并且有那些影响我整个应用程序的隐式和转换。
    • 我也认为在向后兼容性方面不会对 Silhouette 代码库产生任何影响。我可以为此做一个 PoC 分叉。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-11-13
    • 2022-07-25
    • 1970-01-01
    • 2018-12-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多