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
数据库中读取完全相同的数据。
我知道 ScalikeJdbc
和 ScalaJson
都支持使用 Scala
的 案例 class 解析数据es 自动转换.
我的问题是:
ScalikeJdbc
是否支持解析枚举值like ScalaJson
?
- 是否可以使用相同的
case class
来解析 ScalikeJdbc
和 ScalaJson
中的数据,或者它们是否需要不同?我的 case class
问题将包含自定义类型的参数,而这些参数又是 case class
es 本身。这些 case class
es 接受除了 Enum 值 之外的以下类型的参数(基本上,它们不包含完全相同类型的参数,但是 复杂程度 将是相同的):
Int
、String
Option[Int]
, Option[String]
Option[Seq[ (Int, String, Option[Int], Option[String]) ]]
- Enums 可以通过添加 额外的手动验证 来完全消除,尽管最终结果可能不如 [=48] =]整齐。也就是说,一般来说,使用 Enums 是个好主意(特别是从数据库或
JSON
/ XML
文件中读取数据时)或 添加枚举的开销 太多了,无法证明它们的好处?
正如在对该问题的评论中所说,我没有直接从 MySQL
数据库或 JSON
读取 Enums
。显然,这些字段现在在数据库中是简单的 VARCHAR
s,我将验证逻辑移到了我的 Scala
代码中。由于我单独执行验证,因此我用来保存从 MySQL
或 JSON
读取的数据的 case class
es 不再有任何 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 class
es,我可以在 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 您正在使用的语言/库(当时我对 Scala
和 ScalikeJdbc
了解不多),绝对使用 Enum
没有开销(从编码的角度来看);事实上,它们使代码更加清晰。不用说,即使从性能的角度来看,使用 Enum
s 也比使用 String
.
好得多
我需要从 MySQL
Scala
中的数据库。我正在使用 ScalikeJdbc
查询 MySQL
并解析结果集。我在 it's docs 中找不到任何关于 解析枚举类型 的提及(也许我需要更深入地挖掘)。
但是我的目标应用程序需要有两种加载数据的方式:数据库和 JSON
文件。因此,我还使用 ScalaJson
(Play Framework
) 来解析 Json 文件,以便从 MySQL
数据库中读取完全相同的数据。
我知道 ScalikeJdbc
和 ScalaJson
都支持使用 Scala
的 案例 class 解析数据es 自动转换.
我的问题是:
ScalikeJdbc
是否支持解析枚举值likeScalaJson
?- 是否可以使用相同的
case class
来解析ScalikeJdbc
和ScalaJson
中的数据,或者它们是否需要不同?我的case class
问题将包含自定义类型的参数,而这些参数又是case class
es 本身。这些case class
es 接受除了 Enum 值 之外的以下类型的参数(基本上,它们不包含完全相同类型的参数,但是 复杂程度 将是相同的):Int
、String
Option[Int]
,Option[String]
Option[Seq[ (Int, String, Option[Int], Option[String]) ]]
- Enums 可以通过添加 额外的手动验证 来完全消除,尽管最终结果可能不如 [=48] =]整齐。也就是说,一般来说,使用 Enums 是个好主意(特别是从数据库或
JSON
/XML
文件中读取数据时)或 添加枚举的开销 太多了,无法证明它们的好处?
正如在对该问题的评论中所说,我没有直接从 MySQL
数据库或 JSON
读取 Enums
。显然,这些字段现在在数据库中是简单的 VARCHAR
s,我将验证逻辑移到了我的 Scala
代码中。由于我单独执行验证,因此我用来保存从 MySQL
或 JSON
读取的数据的 case class
es 不再有任何 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 class
es,我可以在 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并构建
[=159的case class
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 您正在使用的语言/库(当时我对 Scala
和 ScalikeJdbc
了解不多),绝对使用 Enum
没有开销(从编码的角度来看);事实上,它们使代码更加清晰。不用说,即使从性能的角度来看,使用 Enum
s 也比使用 String
.