Как сказано в комментарии к вопросу, я отказался от чтения Enums
непосредственно из базы данных MySQL
или JSON
. Очевидно, что эти поля теперь являются простыми VARCHAR
в базе данных, и я перенес логику проверки в свой Scala
код. Поскольку я выполняю проверку отдельно, case class
es, которые я использую для хранения данных, считанных из MySQL
или JSON
, больше не имеют полей типа Enum.Value
.
Я бы сказал, что было бы гораздо логичнее иметь Enums
непосредственно в базе данных; но из-за отсутствия простого решения я выбрал этот обходной путь. Это все еще открытый вопрос, и я обновлю ответ, как только найду решение.
Переходя к другой части моего вопроса
Можно ли использовать один и тот же класс case для анализа данных как в ScalikeJdbc, так и в ScalaJson, или они должны быть разными?
Да
Я создал case class
es с companion object
s и могу использовать их для автоматического преобразования как в 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)
Этот метод считывает набор результатов запроса к базе данных и создает object
из case class
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
Наконец, вот фрагмент кода для чтения данных этого класса case из файла Json.
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
Поддерживает ли ScalikeJdbc синтаксический анализ значений Enum, таких как 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
)
.. в общем, стоит ли вообще использовать Enums..
Да, абсолютно
Весь смысл использования типа Enum
заключается в ограничении диапазона значений, которые может принимать переменная. Я не вижу более простого способа обеспечить соблюдение таких правил, кроме Enum
.
Кроме того, если у вас есть достаточное ноу-хау языка/библиотеки, которую вы используете (в то время я мало знал Scala
и ScalikeJdbc
), для использования Enum
не будет абсолютно никаких накладных расходов (с точки зрения кодирования); на самом деле они делают код намного понятнее. Излишне говорить, что даже с точки зрения производительности использование Enum
s намного лучше, чем использование String
.
person
y2k-shubham
schedule
22.02.2018
Enums
в своихcase class
es, мне все равно нужно использовать одни и те жеcase class
es дляScalikeJdbc
иScalaJson
;companion object
этихcase class
es должны расширятьSQLSyntaxSupport[T]
(согласноScalikeJdbc
); который создает неоднозначную ошибку ссылки, когда я добавляю в них методыJson
reads[T]
,writes[T]
и т. д. - person y2k-shubham   schedule 13.02.2018case class
es дляScalikeJdbc
иScalaJson
, анализEnums
с использованиемScalikeJdbc
(и сопоставление их сEnum
, определенным в кодеScala
) все еще остается открытым вопросом. - person y2k-shubham   schedule 26.02.2018