You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ScalikeJdbc是否支持Enum解析?能否与ScalaJson共用Case Class?

ScalikeJdbc Enum Parsing & Shared Case Classes with Play ScalaJson

Great question! Let's break this down clearly: yes, ScalikeJdbc does support Enum parsing (with a small amount of setup), and you absolutely can use the same case class for both ScalikeJdbc database reads and Play ScalaJson parsing. Here's how to make it work smoothly.

1. ScalikeJdbc's Enum Parsing Capabilities

ScalikeJdbc doesn't have automatic Enum mapping for every scenario, but it provides flexible tools to add this support via TypeBinder (for reading from ResultSets) and ParameterBinder (for writing to the database).

Option 1: Use ScalikeJdbc's Built-in EnumTypeBinder

If your database stores Enum values as strings that exactly match your Scala Enum's entry names, use the EnumTypeBinder from the scalikejdbc-enumeration module (ensure it's in your dependencies):

import scalikejdbc._
import scalikejdbc.enumeration._

// Define your Scala Enum
sealed trait UserStatus extends EnumEntry
object UserStatus extends Enum[UserStatus] {
  case object Active extends UserStatus
  case object Inactive extends UserStatus
  case object Pending extends UserStatus

  override def values: Seq[UserStatus] = findValues
}

// Register the implicit TypeBinder for your Enum
implicit val userStatusBinder: TypeBinder[UserStatus] = EnumTypeBinder.byName[UserStatus]

Option 2: Custom TypeBinder for Non-Matching Values

If your database uses numbers or different strings for Enums, create a custom TypeBinder to handle the mapping:

implicit val userStatusBinder: TypeBinder[UserStatus] = new TypeBinder[UserStatus] {
  // Map database value to Scala Enum
  override def apply(rs: java.sql.ResultSet, label: String): UserStatus = {
    val dbValue = rs.getString(label)
    dbValue match {
      case "ACT" => UserStatus.Active
      case "INA" => UserStatus.Inactive
      case "PEN" => UserStatus.Pending
      case _ => throw new IllegalArgumentException(s"Unknown status: $dbValue")
    }
  }

  override def apply(rs: java.sql.ResultSet, index: Int): UserStatus = {
    val dbValue = rs.getString(index)
    // Same matching logic as above
    dbValue match {
      case "ACT" => UserStatus.Active
      case "INA" => UserStatus.Inactive
      case "PEN" => UserStatus.Pending
      case _ => throw new IllegalArgumentException(s"Unknown status: $dbValue")
    }
  }
}

For writing to the database, add a ParameterBinder to convert your Enum back to the database's expected format:

implicit val userStatusParameterBinder: ParameterBinder[UserStatus] = ParameterBinder { (status, stmt, idx) =>
  val dbValue = status match {
    case UserStatus.Active => "ACT"
    case UserStatus.Inactive => "INA"
    case UserStatus.Pending => "PEN"
  }
  stmt.setString(idx, dbValue)
}

2. Sharing the Same Case Class with Play ScalaJson

Your case class doesn't need any modifications to work with both tools—all parsing logic lives in implicit type classes (ScalikeJdbc's TypeBinder and Play Json's Format) that resolve at compile time.

Step 1: Define Your Case Class

Keep it focused on your data model:

case class User(
  id: Long,
  name: Option[String], // Handles optional/nullable fields
  status: UserStatus
)

Step 2: Add Play Json Format for the Enum

Create an implicit Format to enable Play Json parsing for your Enum:

import play.api.libs.json._

implicit val userStatusFormat: Format[UserStatus] = new Format[UserStatus] {
  override def reads(json: JsValue): JsResult[UserStatus] = json match {
    case JsString(value) => 
      UserStatus.values.find(_.entryName == value)
        .map(JsSuccess(_))
        .getOrElse(JsError(s"Invalid status: $value"))
    case _ => JsError("Expected string value for status")
  }

  override def writes(status: UserStatus): JsValue = JsString(status.entryName)
}

// Play Json automatically handles Option fields, no extra setup needed for `name`

Step 3: Use the Case Class with Both Tools

Now you can use the same User case class for database reads and JSON parsing seamlessly:

ScalikeJdbc Query Example

val userId: Long = 123
val user: Option[User] = sql"""
  SELECT id, name, status 
  FROM users 
  WHERE id = $userId
""".map(rs => User(
  rs.long("id"),
  rs.stringOpt("name"), // Handles nullable DB fields
  rs.get[UserStatus]("status") // Uses our implicit TypeBinder
)).single().apply()

Play Json Parsing Example

val userJson = """{
  "id": 123,
  "name": "Alice Smith",
  "status": "Active"
}"""

val parsedUser: User = Json.parse(userJson).as[User]

Key Takeaways

  • ScalikeJdbc supports Enum parsing via built-in or custom TypeBinder implementations.
  • Play ScalaJson requires a custom Format for Enums, but this is straightforward to implement.
  • You can use the exact same case class for both tools—all parsing logic is contained in implicit type classes, not the case class itself.
  • Optional/nullable fields work naturally with both libraries (ScalikeJdbc uses rs.stringOpt etc., Play Json handles Option out of the box).

内容的提问来源于stack exchange,提问作者y2k-shubham

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 03:07:47