【问题标题】:How to persist enum value in slick如何在光滑中保持枚举值
【发布时间】:2023-03-06 00:00:01
【问题描述】:

我有以下枚举:

object LoginStatus extends Enumeration() with BitmaskedEnumeration {
  type LoginStatus = Value
  val Active = Value("A")
  val Inactive = Value("I")
}

我需要保留枚举“A”的值,但是当生成 sql 时结果为 0。 这是表映射:

object LoginTable extends Table[Login]("login") {
  def idLogin = column[Int]("idlogin", O.PrimaryKey, O.AutoInc)
  def cdLogin = column[String]("cdlogin", O.NotNull)
  def cdPass = column[String]("cdPass", O.NotNull)
  def stLogin = column[LoginStatus]("stlogin", O.NotNull, O.DBType("character(1)"))
}

如何持久化枚举值?

我实现了

implicit val charMapper = MappedTypeMapper.base[Char, String](
    b => b.toString(),
    i => i.charAt(0))

  implicit def enum2StringMapper(enum: Enumeration) = MappedTypeMapper.base[enum.Value, Char](
    b => b.toString.charAt(0),
    i => enum.withName(i.toString))

  implicit val LoginStatusMapper = enum2StringMapper(LoginStatus)

但结果:

[error] c.Login - Invalid value for type int : A

【问题讨论】:

标签: scala slick


【解决方案1】:

我个人建议让您自己的类继承自 Scala 的 Enumeration 类,因为这样您就不必为最终使用的每个枚举创建映射器:

这是我目前正在使用的 2.0 代码:

abstract class DBEnum extends Enumeration {

  import slick.jdbc.MappedJdbcType
  import slick.driver.JdbcDriver.simple._

  implicit val enumMapper = MappedJdbcType.base[Value, Int](_.id, this.apply)
}

这也应该适用于 slick 1.0(我还没有测试过):

abstract class DBEnum extends Enumeration {
  implicit val enumMapper = MappedTypeMapper.base[Value, Int](_.id, this.apply)
}

现在,您的枚举只需要从 DBEnum 继承,它应该会减少很多样板。

如果您想使用字符串值而不是 Ints,请相应地编辑代码。

【讨论】:

  • tks @prakhunov,我编辑了您的答案以添加我更改为使用字符串的代码。
  • 请注意,由于github.com/slick/slick/issues/540,此代码似乎不适用于当前版本。您收到错误JdbcProfile has no TypeInfo for type scala.slick.driver.JdbcTypesComponent$MappedJdbcType ... 要解决此问题,请将导入更改为您的特定数据库驱动程序,而不是“jdbc”。例如import scala.slick.driver.HsqldbDriver.simple._ 和 import scala.slick.driver.HsqldbDriver.MappedJdbcType
  • 你说得对,我注意到当我将我的项目更新到最终的 slick 2.0 版本时。我们最初计划支持多个数据库,但遗憾的是现在无法实现。
  • 如果你更喜欢特质: trait EnumMapper { this: Enumeration => implicit val enumMapper = MappedColumnType.base[Value, Int](_.id, this.apply) }
  • 我暂时不能尝试,因为我现在不在电脑上,但是这个答案对于 slick 3.1.0 仍然有效吗?
【解决方案2】:

也许你可以为你的枚举类型创建一个 TypeMapper:

implicit val LoginStatusTypeMapper = MappedTypeMapper.base[LoginStatus.Value, Int](  
  // conversion from LoginStatus to int
  {
    status => status.id
  },
  // conversion back from int to enum
  {
    id => LoginStatus(id)
  }
 )

那么您需要将您的列引用为:

columnLoginStatus.Value

这样,当您从数据库加载数据时,它将被转换回您的枚举。如果你坚持将你的值作为字符存储在数据库中,你只需要创建一个映射到一个字符的映射器并定义你的

【讨论】:

    【解决方案3】:

    经过一些帮助,我找到了解决方案,枚举:

    object LoginStatus extends Enumeration {
    
      def enum2StringMapper(enum: Enumeration) = MappedTypeMapper.base[enum.Value, String](
        b => b.toString,
        i => enum.withName(i))
    
      implicit val LoginStatusMapper = enum2StringMapper(LoginStatus)
    
      type LoginStatus = Value
      val Active = Value("A")
      val Inactive = Value("I")
    }
    

    和表映射:

        import constants.LoginStatus._
    ...
        def stLogin = column[LoginStatus]("stlogin", O.NotNull, O.DBType("character(1)"))
    

    【讨论】:

      【解决方案4】:

      @prakhunov 的回答非常好,也适用于 Slick 3.x(在 3.3.3 上测试)。这是他的答案的变体,它将枚举作为字符串存储在数据库中:

      import slick.jdbc.H2Profile.api._
      
      // DatabaseEnumeration.scala
      abstract class DatabaseEnumeration extends Enumeration {
        implicit val enumerationMapper = MappedColumnType.base[Value, String](_.toString, this.withName)
      }
      
      // ColourType.scala
      object ColourType extends DatabaseEnumeration {
        type ColourType = Value
        val Red, Blue = Value
      }
      
      // NumberType.scala
      object NumberType extends DatabaseEnumeration {
        type NumberType = Value
        val One, Two = Value
      }
      
      // MyTable.scala
      class MyTable(tag: Tag) extends Table[(Int, ColourType, NumberType)](tag, "MYTABLE") {
        def identifier: Rep[Int] = column[Int]("IDENTIFIER", O.PrimaryKey, O.AutoInc)
        def colour: Rep[ColourType] = column[ColourType]("COLOUR")
        def number: Rep[NumberType] = column[NumberType]("NUMBER")
        def * = (identifier, colour, number)
      }
      

      要将枚举存储为整数而不是字符串,如@prakhunov 所示,请使用以下命令:

      abstract class DatabaseEnumeration extends Enumeration {
        implicit val enumerationMapper = MappedColumnType.base[Value, Int](_.id, this.apply)
      }
      

      【讨论】:

        猜你喜欢
        • 2023-04-04
        • 1970-01-01
        • 2020-06-15
        • 1970-01-01
        • 2019-05-29
        • 1970-01-01
        • 1970-01-01
        • 2012-05-05
        • 2014-02-02
        相关资源
        最近更新 更多