roles
,其中填充了用户可能被授予的所有角色。行非常稳定,这意味着很少有人向表中添加新角色。此外,还有一个users
表和一个联接表users_roles
。事实上,roles
表只需要通过向users_roles
添加一条记录来授予用户一些预定义的角色。
roles
表格非常简单:
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创建一个符号
- 创建一个扩展
String
并声明vals的新类型RoleId
为了定义角色ID集,以下是我的选项:
- 使用
Enumeration
- 使用密封特征/密封对象并从中派生case对象
我的持久层使用JOOQ,如果我可以在查询中使用类型安全的RoleId,而无需手动将其转换为String,反之亦然,那就太好了。
对此,最好的解决方案是什么?
我不太确定我能理解你的所有问题,但这样的东西不是解决方案吗?
/** 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
}
}
这是完全类型安全的,如果您需要转到字符串/从字符串返回,则有toString
和fromString
方法。
这种方法的唯一缺点是有很多样板代码,很容易出错-创建一个新的RoleId
但不将其添加到Set
中,名称或大小写错误等。
解决此问题的另一种方法是让SBT从某种配置中自动生成此文件(如果在构建环境中可以访问,甚至可以读取SQL表),就这一部分而言,我对另一个问题的回答可能会有所帮助。