使用case类来解析ScalikeJdbc和ScalaJson中包含枚举的数据

时间:2018-02-01 15:51:16

标签: scala playframework enums scalikejdbc

我需要在*中的MySQL数据库中读取某些枚举值(除了其他常规内容,包括一些可选的空值) 。我使用Scala查询ScalikeJdbc并解析结果集。我在it's docs中找不到解析枚举类型的任何提及(也许我需要深入挖掘)。

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

我知道MySQLScalikeJdbc都支持使用ScalaJson案例类 es来解析数据>自动转换。

我的问题是:

  • Scala是否支持解析枚举值 like ScalaJson
  • 可以使用相同的ScalikeJdbc来解析case classScalikeJdbc中的数据,还是需要将它们区分开来?我的ScalaJson将包含自定义类型的参数,而自定义类型的参数又是case class。除了枚举值之外,这些case class接受以下类型的参数(基本上,它们不包含完全相同类型的参数,但级别的复杂性会完全相同):
    • case classInt
    • StringOption[Int]
    • Option[String]
  • Enums 可以通过添加额外的手动验证完全取消,尽管最终结果可能不会像 neat 那样。也就是说,总的来说,最好使用 Enums (特别是在从数据库或Option[Seq[ (Int, String, Option[Int], Option[String]) ]] / JSON文件中读取数据时)或开销添加枚举太多了,无法证明其好处?

1 个答案:

答案 0 :(得分:0)

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

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

来到我的问题的另一部分

  

可以使用相同的case类来解析ScalikeJdbc中的数据   和ScalaJson还是他们需要不同?

我使用case class创建了companion object es,我可以在ScalikeJdbc以及{{1}中将它们用于自动转换 }}。我发布了一个完整的ScalaJson及其case class,用于此双重用途

注意:此代码示例来自框架,旨在 companion object表从一个位置移动到另一个位置。 [实际生产代码]

案例级:

MySQL

播对象:

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

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

  • 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)的{​​{1}}

  • object

    此方法查询case class数据库正在使用def getTables(db: Db)

  • MySQL

  • ScalikeJdbc

    这些是implicit val dateTimeJsReader = JodaReads.jodaDateReads("yyyyMMddHHmmss") implicit val dateTimeJsReader = JodaReads.jodaDateReads("yyyyMMddHHmmss") 读写转换器(由Joda用于)DateTime ScalaJson参数{ {1}}

  • Joda

  • DateTime

    这些是给定case class读写转换器

最后,这是用于从Json文件

读取此案例类数据的代码片段
implicit val reads = Json.reads[Table]

像我这样的 noobs 的最后一条建议:除非您对implicit val writes = Json.writes[Table](以及case class解析,一般而言)感到满意,否则请避免使用{{1} }方法(上面的代码段使用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 } 方法)以克服像this这样的细微错误。

修改-1

  

ScalikeJdbc是否支持解析像ScalaJson这样的枚举值?

获取ScalaJsonJSON无关:如果您有Json.parse(jsonString).asOpt[T],转换为.as[T]有多难?

这是一个小例子:

Enum.Value

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

  

..总的来说,根本不使用Enums是个好主意。

是的,绝对

拥有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),那绝对没有开销(从编码角度来看)使用Enum;事实上,他们使代码更清晰。毋庸置疑,即使从性能角度来看,使用Enum比使用Scala要好得多。