假设我有一个参考数据表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
值。这是一组字符串,但我想防止使用魔术字符串,并使其更安全。
据我了解,有几种选择:
RoleId
并声明val的新类型String
。为了定义一组角色ID,这些是我的选择:
Enumeration
我在持久层中使用JOOQ,如果可以在查询中使用安全的RoleId类型而无需手动将其转换为String,反之亦然,那就太好了。
什么是最好的解决方案?
答案 0 :(得分:1)
我不太确定我能解决您的所有问题,但是这样的解决方案不是吗?
/** 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 ,并且,如果您需要使用字符串,则可以使用toString
和fromString
方法。
此方法唯一的(big)缺点是很多易于理解的样板代码-创建新的RoleId
而不是将其添加到{{1} },名称或大小写的错别字等。
解决此问题的另一种方法是使 SBT 通过某种配置(即使在构建环境中可以访问SQL表)对该文件自动生成文件,对于该部分{我的{3}}对另一个问题可能会有帮助。