如何在 Scala 中模拟基于字符串的静态 ID 的枚举?

How to model an enum of String based static Ids in Scala?

假设我有一个参考数据 table roles 填充了用户可能被授予的所有角色。行相当 stable,这意味着很少有人向 table 添加新角色。此外还有一个 users table 和一个 join-table users_roles。事实上,roles table 只需要通过向 users_roles.

添加记录来授予用户一些预定义的角色

roles table 很简单:

CREATE TABLE IF NOT EXISTS admin.roles (
  id          CHAR(16) PRIMARY KEY,
  description VARCHAR(256) NOT NULL
);

以下示例描述了一个角色:

INSERT INTO admin.roles VALUES('CS_AGENT', 'A customer service agent');

显然,我的代码中某处需要可能的 id 值。这是一组字符串,但我想防止魔术字符串并使其更安全。

据我了解,有以下几种选择:

为了定义角色 ID 集,这些是我的选项:

我正在为我的持久层使用 JOOQ,如果我可以在我的查询中使用类型安全的 RoleId 而无需手动将其转换为字符串,反之亦然,那就太好了。

最好的解决方案是什么?

我不太确定我是否解决了你所有的问题,但这样的事情不是解决方案吗?

/** Represents a RoleId from the roles table. */
sealed trait RoleId {
  def name: String
  def description: String
  override final def toString: String = name
}

object RoleId {
  case object CS_AGENT extends RoleId {
    override val name = "CS_AGENT"
    override val description = "A customer service agent"
  }
  // Define all other roles...

  /** All roles */
  val allRoles: Set[RoleId] = Set(
    CS_AGENT,
    // All other roles...
  )

  /** Returns an RoleId given its name, if the name is not found this will return a None. */
  def fromString(name: String): Option[RoleId] = name.toUpperCase match {
    case "CS_AGENT" => Some(CS_AGENT)
    // All other cases..
    case _ => None
  }
}

这完全是 typesafe 如果你需要去 to/from 一个字符串有 toStringfromString 方法。

这种方法的唯一 (大) 缺点是有很多样板代码,很容易搞砸 - 创建一个新的 RoleId 但不将其添加到Set、名称或案例中的拼写错误等
解决此问题的另一种方法是使此文件由 SBT 从某种配置 自动生成(如果可以访问,甚至读取 SQL table构建环境),对于我的那部分 到另一个问题可能有帮助。