在数据库中存储多个枚举的最佳方法

9
我有一个名为RoleEnum的枚举类型,其中包含四个值:User(1)、Supervisor(2)、Admin(3)和ITOperator(4)。我有一个公告表,用于存储公告数据(标题、正文、开始和结束日期)。然而,我希望能够添加一个新列,称为Roles,以定义哪些角色的用户可以查看公告。
通常在SQL中存储枚举时,我只使用smallint数据类型,但在这种情况下不起作用,因为一个公告可能会被多个角色看到。
我考虑将Roles列定义为varchar(x),并在存储它们时使用逗号分隔。但是,我不确定这是否是最佳方法。我不想创建一个新表来保存一对多的关系。
有什么建议吗?

4
不要使用逗号分隔的值,否则你之后就必须要解析这些值。使用规范化的表结构就可以了。 - Zane
我们使用简单的数学方法来解决这个问题...我们将枚举值设置为1、3、5、7、9...如果一条信息是给单个组的,则将该消息的值设置为其中一个数字,如果有几个组可以查看该消息,则添加组数,并将该消息的值设置为总和。 - pithhelmet
@pithhelmet 应该在我的帖子中解释一下,目前用户是1、监管员是2、管理员是3,IT操作员是4。问题是,如果公告对用户、管理员和IT操作员可见,或者如果它对所有人都可见,例如对用户等等。 - Justin Adkins
由于不再必要,我已删除了我的指导性注释。相反,我敦促你遵循JDB的解决方案。 - Zane
3个回答

7

如果你关心可维护性,我建议尽可能多地使用第三范式。

角色

RoleID  RoleName
1       User
2       Supervisor
3       Admin
4       ITOperator

公告

AnnouncementID  Title   ...
1               Foo     ...
2               Bar     ...

AnnouncementsVisibility

AnnouncementID  RoleID
1               1
1               2
2               2
2               3
2               4

“^^^^这正是我在我的初始段对OP评论中所表达的意思。向您致以+1先生。” - Zane
虽然我总体上感谢这些建议,但它们并没有回答问题。如果我想要存储枚举值,那么这些值将不会改变,更糟糕的是,每个值在开发时都有特定的含义。因此,如果您为这些枚举值创建一个表,您最终仍将使用枚举来为每个静态表行赋予含义。对于这个具体的问题,解决方案应该是@xxbbcc提供的。 - David Silva-Barrera
@David 我认为你没有理解这个问题。问题是如何在SQL中将一个公告与多个角色关联起来。你不能在SQL中使用标志注释。 - JDB
亲爱的JDB,请再次阅读问题。请注意,他明确要使用Enum。他想使用一个简单的列来存储值,他知道他有多个值(他提到了逗号可能分隔的解决方案)。是的,他可以进行多对多关联,但是将不得不编写很多没有理由或需要的代码。在这种情况下,xxbbcc的解决方案更实用。您不需要任何特殊的SQL注释,只需存储变量的值,只需使用布尔运算符来组合/分解它即可。您的建议总体上是正确的,但这是非常具体的。 - David Silva-Barrera
@DavidSilva-Barrera - 我能理解你的观点。就我个人而言,我认为数据库应该独立存在,不需要过多考虑客户端源代码。我曾参与过几个项目,其中一个现有的数据库需要被保留,但客户端完全重写(例如从桌面到Web)。在列中存储枚举标志对我来说似乎是短视的...在我看来,SQL查询变得更加复杂和难以理解,但我想这归结于个别项目。我坚持我的答案,但承认还有其他观点。 - JDB

4
这是一种可能的解决方案-不能保证是最好的,但不需要新建表。
您可以在枚举上添加[Flags]属性-这使得枚举成为一个位字段,其中单个枚举值可以被掩码在一起。您的枚举将如下所示:
[Flags]
public enum RoleEnum : long
{
    User = 1,
    Supervisor = 2,
    Admin = 4,
    ITOperator = 8
}

您可以使用 "|"(位运算符OR)将多个角色掩码组合在一个单独的64位整数中,然后将其存储在整数字段(bigint)中的数据库中。
RoleEnum userRoles = RoleEnum.User | RoleEnum.Admin;

如果您不需要 64 种可能的角色,您可以使用一个 int 来代替 - 这将给您 32 种可能的不同角色。

这个与数据库中的“魔数”非常接近。如果你有C#源代码,那么你知道它们的含义,但是只有当你有C#源代码时才知道。 - JDB
3
我不认为这是魔数,你要在数据库中存储枚举值的唯一 int 标识符,如果这样做不对,那么将另一个表的主键作为外键存储在另一张表中也是错误的。如果你没有源代码或至少有文档,那你为什么首先要管理那个数据库呢?文章并没有讨论数据库,而是针对源代码中的魔数问题,即使有源代码,也是一个问题。 - David Silva-Barrera

0

只需像Entity Framework一样将它们存储为整数。

查看此处以了解更多信息... MSDN


为什么不再建立一张表呢,这就是数据库存在的意义! - Chris Noffke
我喜欢@xxbbcc的想法,但无法发表评论。 - Chris Noffke

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接