ScalikeJdbc 和 ScalaJson 中使用 case class 解析包含 enum 的数据

Using case class to parse data containing enum in ScalikeJdbc and ScalaJson

我需要从 MySQL Scala 中的数据库。我正在使用 ScalikeJdbc 查询 MySQL 并解析结果集。我在 it's docs 中找不到任何关于 解析枚举类型 的提及(也许我需要更深入地挖掘)。

但是我的目标应用程序需要有两种加载数据的方式:数据库和 JSON 文件。因此,我还使用 ScalaJson (Play Framework) 来解析 Json 文件,以便从 MySQL 数据库中读取完全相同的数据。

我知道 ScalikeJdbcScalaJson 都支持使用 Scala 案例 class 解析数据es 自动转换.


我的问题是:

正如在对该问题的评论中所说,我没有直接从 MySQL 数据库或 JSON 读取 Enums。显然,这些字段现在在数据库中是简单的 VARCHARs,我将验证逻辑移到了我的 Scala 代码中。由于我单独执行验证,因此我用来保存从 MySQLJSON 读取的数据的 case classes 不再有任何 Enum.Value 类型的字段。

我想说直接在数据库中使用 Enums 会更有意义;但由于缺乏简单的解决方案,我选择了这种解决方法。这仍然是一个悬而未决的问题,一旦找到解决方案,我会更新答案。


来到我问题的另一部分

Can the same case class be used for parsing data in both ScalikeJdbc and ScalaJson or do they need to be different?

我用 companion object 创建了 case classes,我可以在 ScalikeJdbc 中将它们用于 automatic-conversion ] 以及 ScalaJson。我发布了一个完整的 case class 以及它的 companion object 服务于这个 双重目的 .

注意:此代码示例来自框架,旨在移动 MySQL 表从 one-location 到另一个。 [实际production-code]

Case-class:

case class Table(dbId: Option[Int] = None,
                 id: Option[Int] = None,
                 name: String,
                 shouldCopy: Option[Boolean] = None,
                 lastUpdated: Option[DateTime] = None
                )

Companion-object:

object Table {

  private def mapResultToTable(rs: WrappedResultSet): Table = Table(
    dbId = rs.intOpt("db_id"),
    id = rs.intOpt("id"),
    name = rs.string("name"),
    shouldCopy = rs.booleanOpt("should_copy"),
    lastUpdated = rs.dateTimeOpt("last_updated").flatMap { zonedDateTime: ZonedDateTime =>
      Some(DateTime.parse(zonedDateTime.format(DateTimeFormatter.ISO_OFFSET_DATE_TIME)).plusMinutes(330))
    }
  )

  def getTables(db: Db)(implicit session: DBSession): Seq[Table] = {
    sql"""
       SELECT
         *
       FROM
         db_name.tables
       WHERE
         db_id = ${db.id} AND
         should_copy = b'1'
       ORDER BY
         name ASC
    """.
      map(mapResultToTable).
      list().
      apply()
  }

  // for Play-Json [Scala-Json]
  implicit val dateTimeJsReader = JodaReads.jodaDateReads("yyyyMMddHHmmss")
  implicit val dateTimeWriter = JodaWrites.jodaDateWrites("dd/MM/yyyy HH:mm:ss")

  implicit val reads = Json.reads[Table]
  implicit val writes = Json.writes[Table]
}

下面是对代码特定部分的解释:

  • def mapResultToTable(rs: WrappedResultSet)

    此方法读取数据库查询的result-set并构建case class

    [=159的object =]
  • def getTables(db: Db)

    此方法查询 MySQL 数据库正在使用 ScalikeJdbc

  • implicit val dateTimeJsReader = JodaReads.jodaDateReads("yyyyMMddHHmmss")

  • implicit val dateTimeJsReader = JodaReads.jodaDateReads("yyyyMMddHHmmss")

    这些是 Joda DateTime read-write 转换器(由 ScalaJson 使用)用于 Joda DateTime case class

  • 的参数
  • implicit val reads = Json.reads[Table]

  • implicit val writes = Json.writes[Table]

    对于给定的 case class

  • ,这些是 read-write 转换器

最后,这里是 code-snippet 用于从 Json 文件

中读取此案例 class 的数据
val tableOpt: Option[Table] = try {
  val rawJsonString: String = Source.fromFile("path/to/file/fileName.json").mkString
  Some(Json.parse(rawJsonString).as[Table])
} catch {
  case ex: Throwable =>
    println(s"Exception while reading Json file: '$ex'")
    None
}

给像我这样的 新手 的最后一条建议:除非你对 ScalaJson(和 JSON 解析,一般而言)感到满意,否则请避免使用Json.parse(jsonString).asOpt[T] 方法(上面的代码片段使用 .as[T] 方法)以克服像 .

这样的细微错误

EDIT-1

Does ScalikeJdbc support parsing Enum values like ScalaJson?

得到Enum.Value真的和ScalikeJdbc没有关系:一旦你有一个String,转换成Enum.Value有多难?

这是一个小例子:

// Enum
object CloudProvider extends Enumeration {

  val AWS: Value = Value("aws")
  val MicrosoftAzure: Value = Value("microsoft-azure")
  val GoogleCloud: Value = Value("google-cloud")
}

// Case Class
case class SiteInfo(website: String, provider: CloudProvider.Value)

// Mapper method
def mapResult(rs: WrappedResultSet): SiteInfo = {
  val website: String = rs.string("website")
  val provider: CloudProvider.Value = CloudProvider.values.
    find(_.toString == rs.string("provider")).
    getOrElse(CloudProvider.AWS)

  SiteInfo(website, provider)
}

很难理解为什么答案就在我面前却看不到:(mapResult方法)


..in general, is it a good idea to use Enums at all..

是的,绝对

Enum 类型的全部意义在于限制变量可以取值的范围。除了 Enum.

之外,我找不到更简单的方法来执行此类规则

此外,一旦您拥有足够的 know-how 您正在使用的语言/库(当时我对 ScalaScalikeJdbc 了解不多),绝对使用 Enum 没有开销(从编码的角度来看);事实上,它们使代码更加清晰。不用说,即使从性能的角度来看,使用 Enums 也比使用 String.

好得多