正如对该问题的评论所述,我不再直接从MySQL 数据库或JSON 读取Enums。显然,这些字段现在在数据库中是简单的VARCHARs,我将验证逻辑移到了我的Scala 代码中。由于我单独执行验证,我用来保存从MySQL 或JSON 读取的数据的case classes 不再有任何Enum.Value 类型字段。
我会说将Enums 直接放在数据库中会更有意义;但由于缺乏简单的解决方案,我选择了这种解决方法。这仍然是一个悬而未决的问题,一旦找到解决方案,我将更新答案。
来到我问题的另一部分
ScalikeJdbc 中是否可以使用同一个 case 类来解析数据
和 ScalaJson 还是需要不同?
是的
我用companion objects 创建了case classes,我可以在ScalikeJdbc 和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)
此方法读取数据库查询的result-set,并构建case class的object
-
def getTables(db: Db)
此方法查询MySQL数据库正在使用ScalikeJdbc
implicit val dateTimeJsReader = JodaReads.jodaDateReads("yyyyMMddHHmmss")
-
implicit val dateTimeJsReader = JodaReads.jodaDateReads("yyyyMMddHHmmss")
这些是Joda DateTime 读写转换器(由ScalaJson 使用)用于Joda DateTime 参数case class
implicit val reads = Json.reads[Table]
-
implicit val writes = Json.writes[Table]
这些是给定case class的读写转换器
最后,这是从Json文件中读取这个案例类数据的code-sn-p
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
}
对像我这样的 noobs 的最后一条建议:除非您对 ScalaJson(和一般的 JSON 解析)感到满意,否则请避免使用 Json.parse(jsonString).asOpt[T] 方法(上面的 sn -p 使用.as[T] 方法)来克服像this 这样的细微错误。
EDIT-1
ScalikeJdbc 是否支持像 ScalaJson 那样解析 Enum 值?
获取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方法)
..总的来说,使用枚举是个好主意吗..
是的,绝对的
拥有Enum 类型的全部意义在于限制变量可以取值的范围。除了Enum,我找不到更简单的方法来执行此类规则。
此外,一旦您掌握了您所使用的语言/库的足够专业知识(当时我对 Scala 和 ScalikeJdbc 了解不多),绝对没有开销(从编码角度来看)使用Enum;事实上,它们使代码更加清晰。不用说,即使从性能角度来看,使用 Enums 也比使用 String 好得多。